Segfault when running hello world shellcode in C program - exploit

sorry if this question sounds dumb but I am very new to shellcoding and I was trying to get a hello world example to work on a 32 bit linux machine.
As this is shellcoding, I used a few tricks to remove null bytes and shorten the code. Here it is:
section .data
section .text
global _start
_start:
;Instead of xor eax,eax
;mov al,0x4
push byte 0x4
pop eax
;xor ebx,ebx
push byte 0x1
pop ebx
;xor ecx,ecx
cdq ; instead of xor edx,edx
;mov al, 0x4
;mov bl, 0x1
mov dl, 0x8
push 0x65726568
push 0x74206948
;mov ecx, esp
push esp
pop ecx
int 0x80
mov al, 0x1
xor ebx,ebx
int 0x80
This code works fine when I compile and link it with the following commands:
$ nasm -f elf print4.asm
$ ld -o print4 -m elf_i386 print4.o
However, I tried running it within the following C code:
$ cat shellcodetest.c
#include
#include
char *shellcode = "\x04\x6a\x58\x66\x01\x6a\x5b\x66\x99\x66\x08\xb2\x68\x68\x68\x65\x69\x48\x54\x66\x59\x66\x80\xcd\x01\xb0\x31\x66\xcd\xdb\x80";
int main(void) {
( *( void(*)() ) shellcode)();
}
$ gcc shellcodetest.c –m32 –z execstack -o shellcodetest
$ ./shellcodetest
Segmentation fault (core dumped)
Could someone please explain what is happening there? I tried running the code in gdb and noticed something weird happening with esp. But as I said before, I still lack experience to really understand what is going on here.
Thanks in advance!

Your shellcode does not work, because it is not entered in the correct endianness. You did not state how you extracted the bytes from the file print4, but both objdump and xxd gives the bytes in correct order.
$ xxd print4 | grep -A1 here
0000060: 6a04 586a 015b 99b2 0868 6865 7265 6848 j.Xj.[...hherehH
0000070: 6920 7454 59cd 80b0 0131 dbcd 8000 2e73 i tTY....1.....s
$ objdump -d print4
print4: file format elf32-i386
Disassembly of section .text:
08048060 <_start>:
8048060: 6a 04 push $0x4
8048062: 58 pop %eax
8048063: 6a 01 push $0x1
...
The changes you need to do is to swap the byte order, '\x04\x6a' -> '\x6a\x04'.
When I run your code with this change, it works!
$ cat shellcodetest.c
char *shellcode = "\x6a\x04\x58\x6a\x01\x5b\x99\xb2\x08\x68\x68\x65\x72\x65\x68\x48\x69\x20\x74\x54\x59\xcd\x80\xb0\x01\x31\xdb\xcd\x80";
int main(void) {
( *( void(*)() ) shellcode)();
}
$ gcc shellcodetest.c -m32 -z execstack -o shellcodetest
$ ./shellcodetest
Hi there$

Related

Can't properly bind socket unless I pass a seemingly incorrect length

The code I've written doesn't work properly unless I pass a seemingly incorrect number to the length argument of bind. It kind of does work; after the accept call I can see it by running netstat, but the port is incorrect. I originally wrote the code in x86 assembly and I then wrote it in C. In both cases, it didn't work.
When calling the function socket, I passed AF_INET (2) as the domain, SOCK_STREAM (1) as the type, and TCP (6) as the protocol.
Here is the code, the one written in C:
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
int main(void) {
unsigned int fd = socket(AF_INET, SOCK_STREAM, 6);
struct sockaddr_in thing = (struct sockaddr_in) {
.sin_family = AF_INET, //2 bytes
.sin_port = 0x2923, //2 bytes
.sin_addr = 0 //4 bytes
};
printf("%zu\n", sizeof thing);
bind(fd, (struct sockaddr*) &thing, 8); //Using 16 instead of 8 fixes the port problem, why?
listen(fd, 1);
accept(fd, 0, 0);
}
To me, 8 looks like the correct length to use. However, 16 seems to be the correct number to use. Why?
Here is the original code written in x86 NASM Assembly:
section .text
global _start
_start:
push byte 6
push byte 1
push byte 2
mov ecx, esp
mov ebx, 1 ;socket
mov eax, 102
int 80h
mov edi, eax ;file descriptor
push dword 0x00000000 ;4 bytes
push word 0x2923 ;2 bytes
push word 2 ;2 bytes
mov ecx, esp
push byte 8 ;Length argument, byte turned into 4 bytes in stack
push ecx
push edi
mov ecx, esp
mov ebx, 2 ;bind
mov eax, 102
int 80h
push byte 1
push edi
mov ecx, esp
mov ebx, 4 ;listen
mov eax, 102
int 80h
push byte 0
push byte 0
push edi
mov ecx, esp
mov ebx, 5 ;accept
mov eax, 102
int 80h
bind(fd, (struct sockaddr*) &thing, 8); //Using 16 instead of 8 fixes the port problem, why?
This code will fail with EINVAL (checked with Linux), but this error is simply ignored by your program. This means no explicit bind will be done.
listen(fd, 1);
accept(fd, 0, 0);
Since the explicit bind failed an implicit bind will be done, effectively meaning that the socket will listen on a random address. That's why it does not seem to work. netstat should show the random port here, not the actually intended one.
Look at the examples in the man page: https://man7.org/linux/man-pages/man2/bind.2.html.
You have to pass the size of the sockaddr_in structure.
bind(fd, (struct sockaddr*) &thing, sizeof(thing));
It's very likely that bind makes an internal check, to ensure that the 3rd parameter is indeed the size of the structure in the 2nd parameter
For AF_INET sockets bind surely knows that the 2nd parameter is a sockaddr_in instance, so it knows what value the 3rd parameter must be.
Really, there's nothing mysterious going on here.

Getting Symbols from crashes at Microsoft Dev Dashboard

The Microsoft Windows Dev Center Dashboard lets me collect stack traces from failures in my native desktop app in the wild.
Unfortunately, minidumps aren't avaialble. I just get a TSV file that (sometimes) has a stack trace in it, which looks like this:
Frame Image Function Offset
0 MyApp 0x2F59A1
1 MyApp 0x11CEA8
2 MyApp 0x11AE74
3 MyApp 0x151289
4 MyApp 0x2A686
5 MyApp 0x180720
6 MyApp 0x1807B6
7 MyApp 0x2E875A
8 MyApp 0x2E8882
9 kernel32 BaseThreadInitThunk 0x24
10 ntdll __RtlUserThreadStart 0x2B
11 ntdll _RtlUserThreadStart 0x1B
To make this uesful, I load the matching binary in WinDbg, figure out the offset plus the base address, and unassemble at the resulting address. If my app loads at 0x00400000, I add 0x2F59A1 to it and get 0x006F59A1. Unassembling there shows me the return address of that stack frame, so I can get some idea of what the crash is about.
Is there a better way? How can I request minidumps from Dev Center? (Microsoft Support says I just can't. Really?) Is there a script to convert at TSV file a usable stack trace so I don't manually evaluate each stack frame? Is there some other way?
I don't know if you can get a .dmp or not google says you can not get one from dash board
the answer below is a modified version of a script
I once used it to disassemble # .map file offsets improvise if needed
it takes the offsets from the column using pandas
creates a command string and uses subprocess to disassemble at that offset
i assume the tsv is a tab seperated value file if not you have some tweaking to do
assuming tab seperated file with data like below
Frame Image Function Offset
0 calc 0x1012
0 calc 0x1015
you can automate the process with some for loops in the code below
edit since i do two subprocess calls the offsets for both forward and backward disassembly are different (ASLR effect )
:\>cat Untitled.py
import pandas as pd
df = pd.read_csv("tsv.txt" , delimiter='\t')
print df
offset = df.Function.unique()[1]
print offset
import subprocess
cmdline = "cdb -c \"ub calc+"+offset+";q\" calc.exe | tail"
print cmdline
output = subprocess.check_output(cmdline ,shell=True )
print output
cmdline = "cdb -c \"u calc+"+offset+";q\" calc.exe | tail"
print cmdline
output = subprocess.check_output(cmdline ,shell=True )
print output
:\>python Untitled.py
Frame Image Function Offset
0 0 calc 0x1012 NaN
1 0 calc 0x1015 NaN
0x1015
cdb -c "ub calc+0x1015;q" calc.exe | tail
calc!_imp__SHGetFolderPathW+0x1:
00f31005 57 push edi
00f31006 1f pop ds
00f31007 7629 jbe calc!_imp__GdipCloneImage+0x2 (00f31032)
00f31009 a1237683dd mov eax,dword ptr ds:[DD837623h]
00f3100e 27 daa
00f3100f 7646 jbe calc!_imp__GdipDeleteGraphics+0x3 (00f31057)
00f31011 1e push ds
00f31012 197600 sbb dword ptr [esi],esi
quit:
cdb -c "u calc+0x1015;q" calc.exe | tail
calc!⌂SHELL32_NULL_THUNK_DATA+0x1:
009b1015 0000 add byte ptr [eax],al
009b1017 007a41 add byte ptr [edx+41h],bh
009b101a 5f pop edi
009b101b 7700 ja calc!⌂SHLWAPI_NULL_THUNK_DATA+0x1 (009b101d)
009b101d 0000 add byte ptr [eax],al
009b101f 005fa1 add byte ptr [edi-5Fh],bl
009b1022 687449a568 push 68A54974h
009b1027 744a je calc!_imp__GdiplusShutdown+0x3 (009b1073)
quit:
:\>

Windbg disassembler address resolution

I was analysing a complete memory dump and I applied Windbg uf command to see what a function does
0: kd> uf profsvc!CUserProfileService::_RegisterGPNotification
This is the part of the output. I wonder why the address in parentheses is different than the address of profsvc!CUserProfileService::_RegisterGPNotification+0x44 which should be
000007fe fb149276
but is
000007fe fb155019.
When I try to unassembled the address 000007fe fb155019 with u it points to
profsvc!CUserProfileService::_RegisterGPNotification+0x44:
I’m really puzzled, any help deeply appreciated.
OUTPUT from WinDBG
….
profsvc!CUserProfileService::_RegisterGPNotification+0x2e:
000007fe`fb14925e ba01000000 mov edx,1
000007fe`fb149263 488bc8 mov rcx,rax
000007fe`fb149266 ff157c410200 call qword ptr [profsvc!_imp_RegisterGPNotification (000007fe`fb16d3e8)]
000007fe`fb14926c 85c0 test eax,eax
000007fe`fb14926e 0f84a5bd0000 je profsvc!CUserProfileService::_RegisterGPNotification+0x44 (**000007fe`fb155019**)
profsvc!CUserProfileService::_RegisterGPNotification+0x40:
000007fe`fb149274 33db xor ebx,ebx
000007fe`fb149276 eb00 jmp profsvc!CUserProfileService::_RegisterGPNotification+0x66 (000007fe`fb149278) Branch
profsvc!CUserProfileService::_RegisterGPNotification+0x66:
000007fe`fb149278 488b0d31b00200 mov rcx,qword ptr [profsvc!WPP_GLOBAL_Control (000007fe`fb1742b0)]
000007fe`fb14927f 488d052ab00200 lea rax,[profsvc!WPP_GLOBAL_Control (000007fe`fb1742b0)]
000007fe`fb149286 483bc8 cmp rcx,rax
000007fe`fb149289 740a je profsvc!CUserProfileService::_RegisterGPNotification+0x94 (000007fe`fb149295) Branch
0: kd> u 000007fe`fb155019
profsvc!CUserProfileService::_RegisterGPNotification+0x44:
000007fe`fb155019 ?? ???
^ Memory access error in 'u 000007fe`fb155019'
This is due to optimization, see the following MSDN article:
https://msdn.microsoft.com/en-us/library/windows/hardware/ff541382(v=vs.85).aspx

Windbg Crash Dump Stack Trace Keeps Every Over Function

So I have a crash dump, and using WinDbg, I am able to get the stack trace. However, it appears to be skipping every other function. For instance if the actual code is:
void a()
{
b();
}
void b()
{
c();
}
void c(){}
The stack trace would have a, and c in the stack frame and not b. Is this expected behavior, and is there something I can do to see the entire stack trace? I have using the command "kn" to view the stack trace.
The compiler may optimize the code. One optimization is to inline methods so that call and ret statements and everything related (push, pop etc.) are removed.
For demonstration purposes, I have added a std::cout statement to your code which we can identify so that the full code now reads
#include "stdafx.h"
#include <iostream>
void c()
{
std::cout << "Hello world";
}
void b()
{
c();
}
void a()
{
b();
}
int _tmain(int argc, _TCHAR* argv[])
{
a();
return 0;
}
Walkthrough in debug build
In a typical debug build, there are no optimizations and you can see the methods. To follow the example, start WinDbg first and run the executable via File/Open executable....
0:000> .symfix e:\debug\symbols
0:000> lm
start end module name
010d0000 010f3000 OptimizedInlined (deferred)
...
0:000> ld OptimizedInlined
Symbols loaded for OptimizedInlined
0:000> x OptimizedInlined!c
010e50c0 OptimizedInlined!c (void)
0:000> bp OptimizedInlined!c
0:000> bl
0 e 010e50c0 0001 (0001) 0:**** OptimizedInlined!c
0:000> g
Breakpoint 0 hit
eax=cccccccc ebx=7efde000 ecx=00000000 edx=00000001 esi=00000000 edi=003ffa00
eip=010e50c0 esp=003ff930 ebp=003ffa00 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
OptimizedInlined!c:
010e50c0 55 push ebp
0:000> u eip L18
OptimizedInlined!c [e:\...\optimizedinlined.cpp # 8]:
010e50c0 55 push ebp
010e50c1 8bec mov ebp,esp
010e50c3 81ecc0000000 sub esp,0C0h
010e50c9 53 push ebx
010e50ca 56 push esi
010e50cb 57 push edi
010e50cc 8dbd40ffffff lea edi,[ebp-0C0h]
010e50d2 b930000000 mov ecx,30h
010e50d7 b8cccccccc mov eax,0CCCCCCCCh
010e50dc f3ab rep stos dword ptr es:[edi]
010e50de 6854ca0e01 push offset OptimizedInlined!`string' (010eca54)
010e50e3 a1e4000f01 mov eax,dword ptr [OptimizedInlined!_imp_?coutstd (010f00e4)]
010e50e8 50 push eax
010e50e9 e8c9c1ffff call OptimizedInlined!ILT+690(??$?6U?$char_traitsDstdstdYAAAV?$basic_ostreamDU?$char_traitsDstd (010e12b7)
010e50ee 83c408 add esp,8
010e50f1 5f pop edi
010e50f2 5e pop esi
010e50f3 5b pop ebx
010e50f4 81c4c0000000 add esp,0C0h
010e50fa 3bec cmp ebp,esp
010e50fc e838c2ffff call OptimizedInlined!ILT+820(__RTC_CheckEsp) (010e1339)
010e5101 8be5 mov esp,ebp
010e5103 5d pop ebp
010e5104 c3 ret
Walkthrough release build
In the release build, see how things change. The WinDbg commands are the same, but the methods c(), b() and a() cannot be found. The std::cout method call has been inlined into wmain():
0:000> .symfix e:\debug\symbols
0:000> lm
start end module name
01360000 01367000 OptimizedInlined (deferred)
...
0:000> ld OptimizedInlined
Symbols loaded for OptimizedInlined
0:000> x OptimizedInlined!c
0:000> x OptimizedInlined!b
0:000> x OptimizedInlined!a
0:000> x OptimizedInlined!wmain
013612a0 OptimizedInlined!wmain (int, wchar_t **)
0:000> bp OptimizedInlined!wmain
0:000> bl
0 e 013612a0 0001 (0001) 0:**** OptimizedInlined!wmain
0:000> g
Breakpoint 0 hit
eax=6142f628 ebx=00000000 ecx=0087a6e8 edx=0019def8 esi=00000001 edi=00000000
eip=013612a0 esp=0042f8f8 ebp=0042f934 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
OptimizedInlined!wmain:
013612a0 8b0d44303601 mov ecx,dword ptr [OptimizedInlined!_imp_?coutstd (01363044)] ds:002b:01363044={MSVCP120!std::cout (646c6198)}
0:000> u eip L4
OptimizedInlined!wmain [e:\...\optimizedinlined.cpp # 23]:
013612a0 8b0d44303601 mov ecx,dword ptr [OptimizedInlined!_imp_?coutstd (01363044)]
013612a6 e895040000 call OptimizedInlined!std::operator<<<std::char_traits<char> > (01361740)
013612ab 33c0 xor eax,eax
013612ad c3 ret
Like already mentioned by Lieven. this is a case where compiler is making function calls inline.
There are 2 things that i would suggest:
a. If you have control over the code and build environment. Build a non-optimized/debug version of the code. This will ensure that compiler does not inline functions on its own.
b. In WinDBG you can see the disassembly under View --> Disassembly. Here you can see that code for function b() is actually in lined under a().
In case you are comfortable with assembly debugging you can get the value of locals as well :)

Analyzing binary taken from memory dump in IDA Pro

I'm having problems with analyzing a simple binary in IDA Pro.
When running a program, i dumped part of its memory (for example, unpacked code section in the memory) into a file, using WinDbg.
I would like to analyze it using IDA, but when trying to just load the binary - it will only show its raw data.
Of course the binary is not a full PE file, so I'm not expecting a deep analysis, just a nicer way to read the disassembly.
So the question is - How can i make IDA disassemble the binary?
Thanks! :)
select an appropriate address and press c
that is MakeCode(Ea); ida will convert the raw bytes to code and disassemble it
pasted below is a simple automation with an idc script but idas automation is imho subpar so you should stick with manual pressing of C in user interface
:dir /b
foo.dmp
foo.idc
:xxd foo.dmp
0000000: 6a10 6830 b780 7ce8 d86d ffff 8365 fc00 j.h0..|..m...e..
0000010: 64a1 1800 0000 8945 e081 7810 001e 0000 d......E..x.....
0000020: 750f 803d 0850 887c 0075 06ff 15f8 1280 u..=.P.|.u......
0000030: 7cff 750c ff55 0850 e8c9 0900 00 |.u..U.P.....
:type foo.idc
#include <idc.idc>
static main (void) {
auto len,temp,fhand;
len = -1; temp = 0;
while (temp < 0x3d && len != 0 ) {
len = MakeCode(temp);
temp = temp+len;
}
fhand = fopen("foo.asm","wb");
GenerateFile(OFILE_LST,fhand,0,0x3d,0x1F);
fclose(fhand);
Wait();
Exit(0);
}
:f:\IDA_FRE_5\idag.exe -c -B -S.\foo.idc foo.dmp
:head -n 30 foo.asm | tail
seg000:00000000 ; Segment type: Pure code
seg000:00000000 seg000 segment byte public 'CODE' use32
seg000:00000000 assume cs:seg000
seg000:00000000 assume es:nothing, ss:nothing, ds:nothing, fs:no thing, gs:nothing
seg000:00000000 push 10h
seg000:00000002 push 7C80B730h
seg000:00000007 call near ptr 0FFFF6DE4h
seg000:0000000C and dword ptr [ebp-4], 0
with windbg you can get the disassembly right from command line like this
:cdb -c ".dvalloc /b 60000000 2000;.readmem foo.dmp 60001000 l?0n61;u 60001000 60001040;q" calc
0:000> cdb: Reading initial command '.dvalloc /b 60000000 2000;.readmem foo.dmp 60001000 l?0n61;u 60001000 60001040;q'
Allocated 2000 bytes starting at 60000000
Reading 3d bytes.
60001000 6a10 push 10h
60001002 6830b7807c push offset kernel32!`string'+0x88 (7c80b730)
60001007 e8d86dffff call 5fff7de4
6000100c 8365fc00 and dword ptr [ebp-4],0
60001010 64a118000000 mov eax,dword ptr fs:[00000018h]
60001016 8945e0 mov dword ptr [ebp-20h],eax
60001019 817810001e0000 cmp dword ptr [eax+10h],1E00h
60001020 750f jne 60001031
60001022 803d0850887c00 cmp byte ptr [kernel32!BaseRunningInServerProcess (7c885008)],0
60001029 7506 jne 60001031
6000102b ff15f812807c call dword ptr [kernel32!_imp__CsrNewThread (7c8012f8)]
60001031 ff750c push dword ptr [ebp+0Ch]
60001034 ff5508 call dword ptr [ebp+8]
60001037 50 push eax
60001038 e8c9090000 call 60001a06
6000103d 0000 add byte ptr [eax],al
6000103f 0000 add byte ptr [eax],al
quit:
ollydbg 1.10 view-> file-> (mask any file) -> foo.dmp -> rightclick -> disassemble