Jump to content
Tuts 4 You

Shellcode+SYSENTER = CALC (SP3)


Recommended Posts

Posted (edited)


#include <windows.h>
//DEV-C++
//link with -masm=intel
asm(".intel_syntax noprefix"); static long csx;
static char* test; int main(void)
{
asm("pop ebp");
asm("pop ebp");
asm("pop ebp"); //asm("push 0x11111111");
//asm("push 0xEEEEEEEE");
//asm("push 0xAAAAAAAA");
//asm("push 0xCCCCCCCC");
//char *test = "\x31\xC9\x51\x68"
//"\x63\x61\x6C\x63"
//"\x54\xB8\xC7\x93"
//"\xC2\x77\xFF\xD0"; asm("push 0xD0FF77C2");
asm("push 0x93C7B854");
asm("push 0x636C6163");
asm("push 0x6851C931");
asm("push 0x004012E6");
asm("mov ebp,0x33333333");
asm("mov edx, esp");
asm("SYSENTER");
asm("push 0");
asm("call _ExitProcess@4");
asm("call esp");
return 0;
}


 

 

nothing too major from what i can tell. But it was neat to use SYSENTER to pop this calc shellcode on XP SP3

seems to go into kernel then back to the user mode call esp. Since the shellcode for calc was placed there in esp, it pops

Maybe a call esp located in ntoskernl would be better to try but the PoC is here to play with

 

and it sucks the mem addresses are hardcoded which means they have a possibility of changing between systems

but shellcode is great for avoiding API

no clean exit (i was too lazy)

 

lastly: we can call esp from ntdll: asm("push 0x7C95D003");     instead asm("push 0x004012E6");

Edited by JMC31337
Posted

Are you practicing for obfuscated code contest? Because yet again I fail to see any security discovery here.

1) This is shellcode you're using:

31C9             XOR ECX,ECX       <-\ 51               PUSH ECX          <-- put 0 to stack to have "calc" string 0-terminated.68 63616C63      PUSH 636C6163     <-- put string "calc" on stack54               PUSH ESP          <-- push pointer to that stringB8 C793C277      MOV EAX,77C293C7  <-- hardcoded address of msvcrt!system APIFFD0             CALL EAX          <-- call msvcrt!system
We can see the same shellcode at http://www.exploit-db.com/exploits/17302/ and http://www.exploit-db.com/exploits/22467/ and in gazillion of other places.

And it's definitely not avoiding APIs.

2) Behaviour of SYSENTER and KiFastSystemCall is well documented, for example here: http://www.geoffchappell.com/studies/windows/km/cpu/sep.htm

Posted (edited)

yea thats pretty much a standard shellcode to pop calc (i never said otherwise)


and yea shellcode does avoid API


 


http://www.symantec.com/connect/articles/windows-syscall-shellcode


 


Syscall shellcode advantages


There are several advantages when using this approach:


 


  • Shellcode doesn't require the use of APIs, due to the fact that it doesn't have to locate API addresses (there is no kernel address finding/no export section parsing/import section parsing, and so on). Due to this "feature" it is able to bypass most of ring3 "buffer overflow prevention systems." Such protection mechanisms usually don't stop the buffer overflow attacks in itself, but instead they mainly hook the most used APIs and check the caller address. Here, such checking would be of no use.
  • Since you are sending the requests directly to the kernel handler and you "jump over" all of those instructions from the Win32 Subsystem, the speed of execution highly increases (although in the era of modern processors, who truly cares about speed of shellcode?).

Syscall shellcode disadvantages


There are also several disadvantages to this approach:


 


  • Size -- this is the main disadvantage. Becase we are "jumping over" all of those subsytem wrappers, we need to code our own ones, and this increases the size of shellcode.
  • Compability -- as has been written above, there exist various implementations from "int 2eh" to "sysenter," depending on the operating system version. Also, the system call number changes together with each Windows version (for more see the References section).

nowhere did i ever say this post ever exploited something... just said it pops calc


and if you can find me another SYSENTER popper post it, because im interested


 


PS: i bet i could code an entire virus using nothing but SYSENTER


Edited by JMC31337
Posted (edited)

here's what ollydbg shows


CPU Disasm

Address   Hex dump          Command                                  Comments

004012DD  |.  0F34          SYSENTER

 

hit F7 and step into that there SYSENTER one time

 

and here is the register output:

 


CPU - main thread, module ntdll

 

EAX C0000005

ECX 00000001

EDX FFFFFFFF

EBX 00004000

ESP 0022FF5C

EBP 33333333

ESI 7E471088

EDI 7E418BD9

EIP 7C95D003 ntdll.7C95D003

 

C 1  ES 0023 32bit 0(FFFFFFFF)

P 1  CS 001B 32bit 0(FFFFFFFF)

A 0  SS 0023 32bit 0(FFFFFFFF)

Z 1  DS 0023 32bit 0(FFFFFFFF)

S 0  FS 003B 32bit 7FFDF000(FFF)

T 0  GS 0000 NULL

D 0

O 0  LastErr 00000002 ERROR_FILE_NOT_FOUND

EFL 00000247 (NO,B,E,BE,NS,PE,GE,LE)

 

ST0 empty +UNORM 4729 5AD74729 5ADA1178

ST1 empty 0.0

ST2 empty 0.0

ST3 empty +UNORM 0054 00000000 01000000

ST4 empty 0.0000000000231729020e-4933

ST5 empty 0.0

ST6 empty 0.0

ST7 empty -UNORM FFF5 00000000 00000000

               3 2 1 0      E S P U O Z D I

FST 0000  Cond 0 0 0 0  Err 0 0 0 0 0 0 0 0 (GT)

FCW 037F  Prec NEAR,64  Mask    1 1 1 1 1 1

Last cmnd 0000:00000000

 

XMM0 0061006D 006F0068 00610054 00000000

XMM1 0061006D 006F0068 00610054 00000000

XMM2 00000000 00000000 00000000 00000000

XMM3 00000000 00000000 00000000 00000000

XMM4 5AD746C1 5AD746AD 0012B53C 0000F920

XMM5 0012B758 5AD753A4 0012B758 5ADA113C

XMM6 00A3808C 00A38444 00A38130 5AD8CD4D

XMM7 5AD75904 0012B77C 003A0900 5AD753FC

                                P U O Z D I

MXCSR 00001F80  FZ 0 DZ 0  Err  0 0 0 0 0 0

                Rnd NEAR   Mask 1 1 1 1 1 1

 


 


That EAX according to Symantec is the syscall ordinal number which says from my experience C0000005 ACCESS VIOLATION


 


but we say whatever, we're gonna keep running this syscall


that calls POP CALCULATOR


 


but hey mayber on your system c0000005 isnt access violation i dunno


or maybe i miss the point of this whole tutorial


 


and the EDX FFFFFFFF:


is MCSFT's wonderful SEH which isnt helping in this situation at all


Edited by JMC31337
Posted

You're mixing apples and oranges.


 


1) As my disassembly clearly shows - your shellcode is using msvcrt API "system". That's an API, not a syscall.


2) You could also read the original PB's article about shellcode using only syscalls: http://pb.specialised.info/all/articles/windows_syscall_shellcode.pdf and then look at your shellcode again.


3) Your OllyDbg "analysis" makes absolutely no sense - for too many reasons to list them all here.


 


My suggestion - read some beginners books first - and then try doing research.


Posted (edited)

You're mixing apples and oranges.

 

1) As my disassembly clearly shows - your shellcode is using msvcrt API "system". That's an API, not a syscall.

2) You could also read the original PB's article about shellcode using only syscalls: http://pb.specialised.info/all/articles/windows_syscall_shellcode.pdf and then look at your shellcode again.

3) Your OllyDbg "analysis" makes absolutely no sense - for too many reasons to list them all here.

 

My suggestion - read some beginners books first - and then try doing research.

 

CPU Disasm

Address   Hex dump          Command                                  Comments

004011E7  |.  89C3          MOV EBX,EAX

004011E9  |.  E8 C2050000   CALL <JMP.&msvcrt._cexit>                ; [MSVCRT._cexit

004011EE  |.  891C24        MOV DWORD PTR SS:[ESP],EBX               ; /ExitCode

004011F1  |.  E8 7A060000   CALL <JMP.&KERNEL32.ExitProcess>         ; \KERNEL32.ExitProcess

 

 

thats where i ended up before exiting with our lil pdf TerminateProcess using SYSENTER

 

so plz.. spare me.. and your tutorial is the same as mine, which hard codes NTDLL mem addresses just like my very original asm code...

Back to MCSFT you go!

Edited by JMC31337
Posted

You're simply imagining things that aren't happening.

Your syscall *is returning to user mode* with an error code of 0xc0000005.

It resumes execution at the address that was pushed on the stack.

That is the offset of your call esp.

Then it runs the code that you pushed on the stack, which calls the hardcoded *API* address in msvcrt.dll to execute calc.exe.

You're not running anything at all via that syscall. You didn't even pass the syscall a valid ID in the first place, which is why you have an error code in eax.

Posted (edited)

fine fine.. then why does your MCSFT windbg says EXPLOITABLE?


 


and how about this:


 


int main()

{

asm("mov eax, 0x101");

asm("push 0x7C81D233");

asm("mov edx,esp");

asm("SYSENTER");

return 0;   

}

 

we're gonna fig this out.. 

 


CPU Disasm

Address   Hex dump          Command                                  Comments

004012BA  |.  B8 01010000   MOV EAX,101

004012BF  |.  68 33D2817C   PUSH 7C81D233

004012C4  |.  89E2          MOV EDX,ESP

004012C6  |.  0F34          SYSENTER

 

then we hit:


CPU Disasm

Address   Hex dump          Command                                  Comments

7C81D233    8BFF            MOV EDI,EDI                              ; BOOL kernel32.TerminateThread(hThread,ExitCode)

 

and cleanly exit


Edited by JMC31337
Posted

First, it will try to call NtTerminateProcess via syscall. Since you're providing invalid parameters, the call will fail with status 0xC0000008 - invalid handle.


It will return to KiFastSystemCallRet - which will then jump to the address you specified (TerminateThread).


 


If you had read anything about syscalls in WinXP (see, for example, link in my post #2), you'd know that.


Posted

asm("push 0x7C81D233");

asm("mov edx,esp");

asm("SYSENTER");

changed the Sysenter to

RET causing the top of stack to be jumped to MSVCRT

whereas:

asm("mov eax, 0x102");

asm("mov edx, 0x7C81D233");

asm("call dword ptr edx"); (or sysenter)

goes to the k32.TerminateThread which then exits

Completely different places

And in the original post i mention it was coming back down to user mode and also never said it was an exploit ... Windbg did

Posted (edited)

*After checking with replacement of SYSENTER and RET i see that it does go to BOOL kernel32.TerminateThread(hThread,ExitCode)


as does the  SYSENTER call ... Guess ill have to code a lil replication virus just for fun if i can; with sysenter


 


but here is a situation in which i get different results with RET:


 


asm("mov eax, 0x102");

asm("mov ebx, 0x7C81D233");

asm("mov edx,ebx");

asm("ret");

takes me to MSVCRT

 

whereas:

asm("mov eax, 0x102");


asm("mov ebx, 0x7C81D233");

asm("mov edx,ebx");

asm("call edx");

takes me to the TerminateThread

 

 

if i try a sysenter i end up in the NtTerminateThread


asm("mov eax, 0x102");

asm("mov ebx, 0x7C81D233");

asm("mov dword ptr [edx],ebx");

asm("SYSENTER");

 

 

here are the printouts before i run the sysenter:


CPU - main thread, module SysTerm

EAX 00000102

ECX 00401310 SysTerm.00401310

EDX 77C61AE8 msvcrt.77C61AE8

EBX 7C81D233 kernel32.TerminateThread

ESP 0022FF60

EBP 0022FF78

ESI 7E471088

EDI 7E418BD9

EIP 004012C6 SysTerm.004012C6

 

 

 

and after the SYSENTER:

CPU - main thread, module kernel32


EAX C00000DB

ECX 00000001

EDX FFFFFFFF

EBX 7C81D233 kernel32.TerminateThread

ESP 77C61AEC msvcrt.77C61AEC

EBP 0022FF78

ESI 0012B3FC

EDI 7C901000 ntdll.RtlEnterCriticalSection

EIP 7C81D233 kernel32.TerminateThread

 

 

Ending with an FFFFFFFF and hang app-ing my olly (however, just running the exe causes no probs)




Edited by JMC31337
Posted

and to take it to the next level


 


asm("mov eax, 0x102");

asm("mov ebx, 0x7C81D233");

asm("mov dword ptr [edx],ebx");

asm("push edx");

asm("SYSENTER");

takes me to the TerminateThread

 

 


asm("mov eax, 0x102");

asm("mov ebx, 0x7C81D233");

asm("mov dword ptr [edx],ebx");

asm("push edx");

asm("ret");

does not take me to Terminate Thread

Posted

Yes, you really took it to the next level. You discovered that "ret" instruction actually returns and "call" instruction actually calls. Great work!


In next few months maybe you'll learn the difference between "mov edx, ebx" and "mov dword ptr [edx], ebx". But until then...


 


Oh well...


  • Like 1
Posted

asm("SYSENTER");

Seems to call the ptr to edx

Whereas push that edx onto the stack and calling that with a RET

Does not goto the ptr of edx

So SYSENTER goes to ptr edx

RET does not, unless you push dword ptr

So... It has nothing to do with call jmp and everything to do with how SYSENTER is handled in the system... I'll try to do a kernel create writefile just to play...

Somehow you both came at it like this was some exploit when from the gate I said it was nothing serious ... But thanks for not bringing anything to the table besides a PDF that I already posted, and bashing me for playing with shellcode

Posted (edited)

this is SYSENTER calling LoadLibrary


 


char *xnt = "ntdll.dll";
 
int main()
{
asm("xor eax,eax");
asm("xor ebx,ebx");
asm("xor ecx,ecx");
asm("xor edx,edx");
asm("push dword ptr _xnt");
asm("push 0");
asm("push 0x7C801D7B");
asm("mov eax,[esp+8]");
asm("mov dword ptr [esp+12], eax");
asm("mov edx,esp");
asm("mov dword ptr [esp+0x04],0x004012E3");
asm("SYSENTER");
asm("ret");
}
Edited by JMC31337
Posted

Again you are imagining things that aren't happening. SYSENTER is not calling LoadLibrary.

Re-read posts #7 and #9, they describe what's really happening. Re-read document I linked in #2.

If you still don't get it, I don't know who/what can help you.

Posted (edited)

Again you are imagining things that aren't happening. SYSENTER is not calling LoadLibrary.

Re-read posts #7 and #9, they describe what's really happening. Re-read document I linked in #2.

If you still don't get it, I don't know who/what can help you.

yea you're not hiding this one there buddy:

 

CPU Disasm
Address   Hex dump          Command                                  Comments
004012E1  |.  0F34          SYSENTER
 
there is sysenter  -> 
 
 
CPU Disasm
Address   Hex dump          Command                                  Comments
7C801D7B    8BFF            MOV EDI,EDI                              ; HANDLE kernel32.LoadLibraryA(FileName)
 

which further loads up the NTDLL file for me:

 

CPU - main thread, module kernel32
 
EAX 7C900000 ntdll.7C900000
 
and lets dump that just to be sure:
 
CPU DumpAddress   Hex dump                                         ASCII7C900000  4D 5A 90 00|03 00 00 00|04 00 00 00|FF FF 00 00| MZ.........7C900010  B8 00 00 00|00 00 00 00|40 00 00 00|00 00 00 00| .......@.......7C900020  00 00 00 00|00 00 00 00|00 00 00 00|00 00 00 00| ................7C900030  00 00 00 00|00 00 00 00|00 00 00 00|D0 00 00 00| ...............7C900040  0E 1F BA 0E|00 B4 09 CD|21 B8 01 4C|CD 21 54 68| ..!L!Th7C900050  69 73 20 70|72 6F 67 72|61 6D 20 63|61 6E 6E 6F| is program canno7C900060  74 20 62 65|20 72 75 6E|20 69 6E 20|44 4F 53 20| t be run in DOS7C900070  6D 6F 64 65|2E 0D 0D 0A|24                       mode....$
 
sysenter doesnt just CALL ESP, it calls EDX
And its the only OPCODE im using to "CALL" something   (hence SYSTEM CALL)
onward with GetProcAddress then ZwQuerySystemInformation then ZwCreateFile so i can use nothing but Kernel calls to write a 0-byte file to your C drive root
Edited by JMC31337
Posted (edited)

maybe these two pictures will clear it up. In both cases we are standing at the sysenter command, if you hit f8 now, the effect in question will occur: we will return from sysenter with an error code and eip will be eip == LoadLibraryA == [edx], and because of your "mov edx, esp" also edx == esp => [edx] == [esp].

 

 

lv54r64.png

 

 

now, if you had read Kao's link, you would have read this:

 

 

When SYSEXIT is called, CS is set to IA32_SYSENTER_CS+16. EIP is set to EDX. SS is set to IA32_SYSENTER_CS+24, and ESP is set to ECX.

 

 

 

and indeed, after the sysenter eip == [edx] == LoadLibraryA

 

 

To prove this to you, if have altered the situation a tiny little bit: edx == [esp+4] == LoadLibraryW.

 

picture:

 

 

meBgXyu.png

 

and sure enough, once you step over the sysenter, you will be at LoadLibraryW. Because LoadLibraryW == eip == [edx], as per the documentation.

 

 

which is pretty much what Peter Ferrier told you earlier:

 

Your syscall *is returning to user mode* with an error code of 0xc0000005. It resumes execution at the address that was pushed on the stack.

 

 

 

alright? :)
 

Edited by deepzero
Posted (edited)

and i understand that its just a user mode call and that we havent ran anything as SYSTEM (like an Kernel APC process giving NTAUTHORITY/SYSTEM as the user)


 


but what im trying to do is use that fact that the c0000005 access violation DOESNT kick it back to the program space until after the loadlibrary loads ntdll


sysenter kicks into a syscall which then keeps on running loadlibrary until its finished then kicking it back to our program user mode space


 


thats why i added the RET after sysenter.. it doesnt end up at RET until AFTER SYSENTER does its thing


 


post-54883-0-06337500-1386273059_thumb.p


 


 


 


now if that c000005 stopped the sysenter with that ACCESS VIOLATION .,.. loadlibrary would never grab me my ntdll module address but it still lets the code continue... at first i called into the NOP region above the loadlibrary and let it nop sled into the LoadLibrary ... if that C000005 would stop the sysenter it would never sled down the nops into the LoadLibrary.. it should not allow me to do that.. once it access violations out, that whole process should stop running .. at one point it was just calling into load and then coming back down, and because i didnt have the ESP correct (it was pointing again at SYSENTER) it SYSENTER looped on me...


but the 2nd time sysenter did its thing the ESP changed and crapped out on me.. which is why i added that push address pointing to the RET statement


Edited by JMC31337
Posted

you dont call anything.

 

thats why i added the RET after sysenter.. it doesnt end up at RET until AFTER SYSENTER does its thing

 

 

it never hits that ret after sysenter. When sysenter returns to usermode, it doesnt continue after the sysenter instruction, it continues at [edx].

 

 

Now, if [edx] happens to point to LoadLibraryA, it will continue there. And if your stack *happens to be* layed out in a way that it returns to address x after the LoadLibraryA call, then it will continue at that address x. But that is standard execution and has nothing to do with sysret.
Since you are providing  invalid arguments for the syscal anyways, you can replace it by

jmp dword [edx]

jmp,  not call.

Posted

on this system it gets to that ret


 


and that ret was placed there by me to see what happens after sysenter comes back down.. here lemme add something else.. like some pops and show ya it still flows


Posted (edited)

take a look at the EIP


poiting to the RET about to be called


 


 


 


post-54883-0-50411000-1386276381_thumb.p


 


i added that breakpoint after sysenter (again to help me see what the EAX return was  which is the NTDLL module base address which then helps with GetProcAddress) [but i left that register printout "out" of the pic]


Edited by JMC31337
Posted

that is because of the way you set up your stack. Replace sysenter by jmp [edx] and you will observe the same effect.


Posted

naaa naaa lets not give the run-around reply here:


 


"it never hits that ret after sysenter. When sysenter returns to usermode, it doesnt continue after the sysenter instruction, it continues at [edx]."


 


it continues after the sysenter instruction okay.. and ultimately, all im doing is using the sysenter to GO SOMEWHERE ...


 


and the "jmp [edx]" is just another obfuscated way of doing the SAME SYSENTER (go somewhere) routine


could very well jmp [eax] if its loaded right and end up at the same place... 


but nice spin-master reply...


 


"that is because of the way you set up your stack"  


 


of course!


im the one writing the thing.... anyways.. this argument ran its course.. lets argue again over this after i do a lil GetProcAddressing


its a good time....


Posted (edited)
to GO SOMEWHERE ...

 

 

correct, namely to [edx].

 

and the "jmp [edx]" is just another obfuscated way of doing the SAME SYSENTER (go somewhere) routine

 

 

correct, in this limited case sysenter == jmp [edx]

 

 

could very well jmp [eax] if its loaded right and end up at the same place...

 

no, it's always [edx].

 

 

 

I want to stress again that execution *never* continues after the sysenter. It will continue at the address given on the stack. you set that here:

 

move [locale.8], 4012e3

 

4012e3 *happens* to point after the sysenter - but you can use any other address in its place.

Edited by deepzero

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...