x86-64 buffer overflow exploits and the borrowed code chunks - SuSE
x86-64 buffer overflow exploits and the borrowed code chunks - SuSE
x86-64 buffer overflow exploits and the borrowed code chunks - SuSE
Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
6 SINGLE WRITE EXPLOITS 9<br />
48 die("bind");<br />
49 if (listen(sock, 10) < 0)<br />
50 die("listen");<br />
51 signal(SIGCHLD, sigchld);<br />
52 for (;;) {<br />
53 if ((afd = accept(sock, NULL, 0)) < 0 && errno != EINTR)<br />
54 die("accept");<br />
55 if (afd < 0)<br />
56 continue;<br />
57 if (fork() == 0) {<br />
58 h<strong>and</strong>le_connection(afd);<br />
59 exit(0);<br />
60 }<br />
61 close(afd);<br />
62 }<br />
63 return 0;<br />
<strong>64</strong> }<br />
An exploiting client has to fill val1 <strong>and</strong> val2 with proper values. Most<br />
of <strong>the</strong> time <strong>the</strong> Global Offset Table GOT is <strong>the</strong> place of choice to write<br />
values to. A disassembly of <strong>the</strong> new server2 binary shows why.<br />
0000000000400868 :<br />
400868: ff 25 8a 09 10 00 jmpq *1051018(%rip) # 5011f8 <br />
40086e: 68 04 00 00 00 pushq $0x4<br />
400873: e9 a0 ff ff ff jmpq 400818 <br />
When write() is called, transfer is controlled to <strong>the</strong> write() entry in <strong>the</strong><br />
Procedure Linkage Table PLT. This is due to <strong>the</strong> position independent<br />
<strong>code</strong>, please see [2]. The <strong>code</strong> looks up <strong>the</strong> real address to jump to from<br />
<strong>the</strong> GOT. The slot which holds <strong>the</strong> address of glibc’s write() is at address<br />
0x5011f8. If we fill this address with an address of our own, control<br />
is transfered <strong>the</strong>re. However, we again face <strong>the</strong> problem that we can not<br />
execute any shell<strong>code</strong> due to restrictive page protections. We have to use<br />
<strong>the</strong> <strong>code</strong> <strong>chunks</strong> borrow technique in some variant. The trick is here to<br />
shift <strong>the</strong> stack frame upwards to a stack location where we control <strong>the</strong><br />
content. This location is buf in this example but in a real server it could<br />
be some o<strong>the</strong>r <strong>buffer</strong> some functions upwards in <strong>the</strong> calling chain as well.<br />
Basically <strong>the</strong> same technique called stack pointer lifting was described<br />
in [5] but this time we use it to not exploit a stack based <strong>overflow</strong> but a<br />
single-write failure. How can we lift <strong>the</strong> stack pointer? By jumping in a<br />
appropriate function outro. We just have to find out how many bytes <strong>the</strong><br />
stack pointer has to be lifted. If I calculate correctly it has to be at least<br />
two <strong>64</strong>-bit values (val1 <strong>and</strong> val2) plus a saved return address from <strong>the</strong> write<br />
call = 3*sizeof(u int<strong>64</strong> t) = 3*8 = 24 Bytes. At least. Then %rsp points<br />
directly into buf which is under control of <strong>the</strong> attacker <strong>and</strong> <strong>the</strong> game starts<br />
again.<br />
Some <strong>code</strong> snippets from glibc which shows that %rsp can be lifted at<br />
almost arbitrary amounts:<br />
48158: 48 81 c4 d8 00 00 00 add $0xd8,%rsp<br />
4815f: c3 retq<br />
4c8f5: 48 81 c4 a8 82 00 00 add $0x82a8,%rsp<br />
4c8fc: c3 retq<br />
NO-NX