01.04.2015 Views

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

SHOW MORE
SHOW LESS

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

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!