Category: Allgemeines


stunnel or my lack of long term memory

I know this is really basic stuff but I need to take a note here because I always forget this syntax.

stunnel3 -d 8443 -r 192.168.1.10:443 -c

To chat with a, let’s say,  SSL enabled web server through a connection to localhost (-d parameter defaults to localhost if no IP is selected).

Originally, stunnel3 was intended to wrap the connection for not SSL capable services, so in order to use it for a more pentest suited perspective we must explicitly say that we are in “client” mode. Therefore the -c modifier.

openSSH chaos

The other day I was asked about the best way to configure the permissions/ownership of the SSH auth_keys file.

There’s a lot of controversy around this topic and the usual method “I’ll look what Google says” doesn’t help very much in this case. There are a lot of references of technical blogs which recommend opposite solutions… Well, we all know how reliable are personal techie blogs, don’t we? ;)

When dealing with opensource and having a very specific question is better to check the source code

Having an error message, like it was the case, helps by allowing us to grep.

carlos@ubuntu-server-1:~/code/openssh-5.1p1$ grep -in “bad ownership or modes for directory” *
auth.c:454:                         “bad ownership or modes for directory %s”, buf);

From openssh-5.1p1′s auth.c:

/*
* Check a given file for security. This is defined as all components
* of the path to the file must be owned by either the owner of
* of the file or root and no directories must be group or world writable.

*
* XXX Should any specific check be done for sym links ?
*
* Takes an open file descriptor, the file name, a uid and and
* error buffer plus max size as arguments.
*
* Returns 0 on success and -1 on failure
*/
static int
secure_filename(FILE *f, const char *file, struct passwd *pw,
char *err, size_t errlen)
{
uid_t uid = pw->pw_uid;
char buf[MAXPATHLEN], homedir[MAXPATHLEN];
char *cp;
int comparehome = 0;
struct stat st;

if (realpath(file, buf) == NULL) {
snprintf(err, errlen, “realpath %s failed: %s”, file,
strerror(errno));
return -1;
}
if (realpath(pw->pw_dir, homedir) != NULL)
comparehome = 1;

/* check the open file to avoid races */
if (fstat(fileno(f), &st) < 0 ||
(st.st_uid != 0 && st.st_uid != uid) ||
(st.st_mode & 022) != 0) {
snprintf(err, errlen, “bad ownership or modes for file %s”,
buf);
return -1;
}

/* for each component of the canonical path, walking upwards */
for (;;) {                                                                         // An infite loop :-S
if ((cp = dirname(buf)) == NULL) {                                     // strips the non-directory parts
snprintf(err, errlen, “dirname() failed”);
return -1;                                                              // this breaks the infinite loop
}
strlcpy(buf, cp, sizeof(buf));                                                  // kind of strncpy() but BSD compatible

debug3(“secure_filename: checking ‘%s’”, buf);             // “buf” contains the directory name now
if (stat(buf, &st) < 0 ||                                                // reads dir’s info and places into structure
(st.st_uid != 0 && st.st_uid != uid) ||                                 // and here is the check we’re looking for :)
(st.st_mode & 022) != 0) {
snprintf(err, errlen,
bad ownership or modes for directory %s”, buf);
return -1;
}

[...]
return 0;
}

Also if

st.st_uid != 0 && st.st_uid != uid

we have a problem. That means the UID of the directory’s owner must be either the file’s owner itself or an user with UID 0 (root and alike) for every directory all along the descendent path.

Another good example of the geek maxim: “Use the source, Luke” ;)

Freaking out a BITs

Today I was playing with my Check Point NGX Lab at home (yes, people can have that in real life) when some funny connections got my attention (in a freaky way).

Do you see that huge amount of HTTP connections? <- This is a rethorical question, by the way.

All of them originate from my machine and connect to an IP address in the range 74.125.0.0/16. A quick whois query for this address shows the following result (surprise…)

carlos@dell:~$ whois 74.125.98.38
[Querying whois.arin.net]
[whois.arin.net]
#
# Query terms are ambiguous.  The query is assumed to be:
#     “n 74.125.98.38″
#
# Use “?” to get help.
#
#
# The following results may also be obtained via:
# http://whois.arin.net/rest/nets;q=74.125.98.38?showDetails=true&showARIN=false
#
NetRange:       74.125.0.0 – 74.125.255.255
CIDR:           74.125.0.0/16
OriginAS:
NetName:        GOOGLE
NetHandle:      NET-74-125-0-0-1
Parent:         NET-74-0-0-0-0
NetType:        Direct Allocation
NameServer:     NS2.GOOGLE.COM
NameServer:     NS3.GOOGLE.COM
NameServer:     NS4.GOOGLE.COM
NameServer:     NS1.GOOGLE.COM
RegDate:        2007-03-13
Updated:        2007-05-22
Ref:            http://whois.arin.net/rest/net/NET-74-125-0-0-1
OrgName:        Google Inc.
OrgId:          GOGL
Address:        1600 Amphitheatre Parkway
City:           Mountain View
StateProv:      CA
PostalCode:     94043
Country:        US
[...]
WTF was this? Connecting to a registered Google IP address, it couldn’t be ordinary Malware… Google Malware? ;)
So it was time for Microsoft beloved Sysinternals Suite (I freaking love that software, VIVA Mark Russinovich!)
First at all, which process was initiating the connections?
TCPView showed that svchost, PID 1032 was doing this. Double WTF?
svchost.exe named “services host” is an skeleton for Windows services. Since these are implemented as DLLs and not complete executables, they need a harness to run. That’s why Process Explorer lists so many processes inside them.
At the time this happened the process GoogleUpdater.exe was hanging as well from this process tree. This was already a hint, I was actually on the right track but this process had a completely different PID. Thus it looked like, somehow, GoogleUpdater.exe was making use of any of these services to acomplish its task.
Time to check what the hell these small HTTP packets were. I downloaded Wireshark.
Before even download Wireshark completely, I got another clue. While the 17MB of the (beloved) packet analyzer were on its way, the quick flow of small HTTP packet decreased drastically, almost stopped. If this was some kind of malware it was a really polite one, because it looked like it was leaving the bandwidth available to my download…
Using the “Follow TCP Stream” feature of Wireshark (isn’t that just cool?) I got a good view of what was going on behind the stages…
The system was downloading small pieces of the Google Chrome installer (check the “375.125″ inside the URL). You can see in the HTTP response that it is actually an application/x-msdos-program of length 14285 bytes.
But the really interesting part is the User-Agent the systems is using in these HTTP requests: “Microsoft BITS/6.7″.
Going back to Process Explorer, we confirm that BITS is indeed one of the services hosted in that svchost.exe instance.
And this is what MSDN has to say about the BITS service:
Background Intelligent Transfer Service (BITS) transfers files (downloads or uploads) between a client and server and provides progress information related to the transfers. You can also download files from a peer.
The next time I opened Chrome and checked the version, this is what I (unsurprisingly) found:
Also, neither malware nor evil Google eavesdropping but enough to scare a chickenshit like me ;)

Playing with gdb. Reverse engineer your way.

Playing a very basic level of a known wargame the other day I was trying to solve the following problem:

Given an executable (ELF, Linux) which accepts a password as an argument and verifies if this is correct, find this string. As most of the problems, it’s quite easy if you have the right tools (and knowledge of course).
Anyway, I thought the solution(s) would make a nice blog entry, so here it is!

In order to play around with it in my own Ubuntu, I wrote a very simple C program, named pass_cli.c


carlos@dell:~/Dropbox/hacking/wargames$ cat pass_cli.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int
main(int argc, char **argv)
{
char password[] = “yomama”;

if(argc < 2)
{
printf(“Usage: %s <password>\n”, argv[0]);
exit(1);
}

if(strncmp(argv[1], password, strlen(password)))
{
printf(“FAIL\n”);
exit(1);
} else {

printf(“WIN\n”);
return(0);
}

return(0); // never reached :)

}

I compiled the program with no special options.

carlos@dell:~/Dropbox/hacking/wargames$ file pass_cli
pass_cli: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, not stripped

A first tool of the trade when you are looking for strings in a binary is strings, which will look for strings of printable characters inside the binary.

carlos@dell:~/Dropbox/hacking/wargames$ strings pass_cli
/lib/ld-linux.so.2
`:6K*
__gmon_start__
libc.so.6
_IO_stdin_used
exit
strncmp
puts
printf
strlen
__libc_start_main
GLIBC_2.0
PTRh`
yomaf
[^_]
Usage: %s <password>
FAIL

Well, we cannot find the password here (and even if it were displayed here, how could you identify it?) but that gave us some preliminar information about the program. We can see some familiar libc functions (printf, strlen, strncmp, etc.), strncmp will be of interest a bit later.

Another method you could have tried is for example to dump the contents of the .text section inside the binary. This is actually the same idea behind the use of strings, just a lot messier ;)
Remember that the .text section of a binary contains the machine instructions (the compiled code) but that doesn’t mean the strings are neccesarily stored in a readable way. Anyway we could check the contents of this section with the help of objdump.

carlos@dell:~/Dropbox/hacking/wargames$ objdump
Usage: objdump <option(s)> <file(s)>
Display information from object <file(s)>.
At least one of the following switches must be given:
-a, –archive-headers    Display archive header information
-f, –file-headers       Display the contents of the overall file header
-p, –private-headers    Display object format specific file header contents
-h, –[section-]headers  Display the contents of the section headers
-x, –all-headers        Display the contents of all headers
-d, –disassemble        Display assembler contents of executable sections
-D, –disassemble-all    Display assembler contents of all sections
-S, –source             Intermix source code with disassembly
-s, –full-contents      Display the full contents of all sections requested
-g, –debugging          Display debug information in object file
-e, –debugging-tags     Display debug information using ctags style
-G, –stabs              Display (in raw form) any STABS info in the file
-W[lLiaprmfFsoR] or
–dwarf[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=str,=loc,=Ranges]
Display DWARF info in the file
-t, –syms               Display the contents of the symbol table(s)
-T, –dynamic-syms       Display the contents of the dynamic symbol table
-r, –reloc              Display the relocation entries in the file
-R, –dynamic-reloc      Display the dynamic relocation entries in the file
@<file>                  Read options from <file>
-v, –version            Display this program’s version number
-i, –info               List object formats and architectures supported
-H, –help               Display this information

carlos@dell:~/Dropbox/hacking/wargames$ objdump -h pass_cli

pass_cli:     file format elf32-i386

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
0 .interp       00000013  08048134  08048134  00000134  2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .note.ABI-tag 00000020  08048148  08048148  00000148  2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA

[...]

11 .init         00000030  0804834c  0804834c  0000034c  2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
12 .plt          00000080  0804837c  0804837c  0000037c  2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
13 .text         000001fc  08048400  08048400  00000400  2**4   <—- here
CONTENTS, ALLOC, LOAD, READONLY, CODE
14 .fini         0000001c  080485fc  080485fc  000005fc  2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE

[...]

This section starts at the address 0×08048400, that is, the offset is 0×400 (the start virtual address is 0×08048000)

Armed with this knowledge we could hexdump this section and manually inspect it

carlos@dell:~/Dropbox/hacking/wargames$ hexdump -C -s 0×400 pass_cli | less

00000400  31 ed 5e 89 e1 83 e4 f0  50 54 52 68 60 85 04 08  |1.^…..PTRh`…|
00000410  68 70 85 04 08 51 56 68  b4 84 04 08 e8 7b ff ff  |hp…QVh…..{..|
[...]
000004a0  00 00 00 00 85 c0 74 09  c7 04 24 1c 9f 04 08 ff  |……t…$…..|
000004b0  d0 c9 c3 90 55 89 e5 83  e4 f0 83 ec 20 c7 44 24  |….U……. .D$|
000004c0  19 79 6f 6d 61 66 c7 44  24 1d 6d 61 c6 44 24 1f  |.yomaf.D$.ma.D$.| <—   :(
000004d0  00 83 7d 08 01 7f 22 8b  45 0c 8b 10 b8 20 86 04  |..}…”.E…. ..|
000004e0  08 89 54 24 04 89 04 24  e8 cf fe ff ff c7 04 24  |..T$…$…….$|
[...]
00000600  83 ec 04 e8 00 00 00 00  5b 81 c3 ec 19 00 00 e8  |……..[.......|
00000610  1c fe ff ff 59 5b c9 c3  03 00 00 00 01 00 02 00  |....Y[..........|
00000620  55 73 61 67 65 3a 20 25  73 20 3c 70 61 73 73 77  |Usage: %s <passw|
00000630  6f 72 64 3e 0a 00 46 41  49 4c 00 57 49 4e 00 00  |ord>..FAIL.WIN..|
00000640  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

As we can see, the string isn't stored in a readable format, as expected :(
A very useful tool in this case is "ltrace" for we can monitor every system call (with the corresponding arguments!)

carlos@dell:~/Dropbox/hacking/wargames$ ltrace ./pass_cli AAAAA
__libc_start_main(0x80484b4, 2, 0xbf952854, 0x8048570, 0x8048560 <unfinished ...>
strlen("yomama")                                                   = 6
strncmp("AAAAA", "yomama", 6)                                      = -1      <--- TA-DA!!!! :)
puts("FAIL"FAIL
)                                                       = 5
exit(1 <unfinished ...>
+++ exited (status 1) +++

But what if our system doesn't have this tool? Then we have to take the heavy weapons and perform some elegant debugging :)

carlos@dell:~/Dropbox/hacking/wargames$ objdump -T pass_cli

pass_cli:     file format elf32-i386

DYNAMIC SYMBOL TABLE:
00000000  w   D  *UND*  00000000              __gmon_start__
00000000      DF *UND*  00000000  GLIBC_2.0   __libc_start_main
00000000      DF *UND*  00000000  GLIBC_2.0   strlen
00000000      DF *UND*  00000000  GLIBC_2.0   printf
00000000      DF *UND*  00000000  GLIBC_2.0   puts
00000000      DF *UND*  00000000  GLIBC_2.0   strncmp     <---- idea!
00000000      DF *UND*  00000000  GLIBC_2.0   exit
0804861c g    DO .rodata        00000004  Base        _IO_stdin_used

We have very good reasons to suspect that strncmp is being used to check our input against the password so let's start the program in gdb and quickly disassemble it in order to localize the call to strncmp.

carlos@dell:~/Dropbox/hacking/wargames$ gdb -q ./pass_cli
Reading symbols from /home/carlos/Dropbox/hacking/wargames/pass_cli...(no debugging symbols found)...done.

(gdb) set disassembly-flavor intel <---- PLEASE ;)
(gdb) disass main
Dump of assembler code for function main:
0x080484b4 <+0>: push ebp
0x080484b5 <+1>: mov ebp,esp
0x080484b7 <+3>: and esp,0xfffffff0
0x080484ba <+6>: sub esp,0x20
0x080484bd <+9>: mov DWORD PTR [esp+0x19],0x616d6f79
0x080484c5 <+17>: mov WORD PTR [esp+0x1d],0x616d
0x080484cc <+24>: mov BYTE PTR [esp+0x1f],0×0
0x080484d1 <+29>: cmp DWORD PTR [ebp+0x8],0×1
0x080484d5 <+33>: jg 0x80484f9
0x080484d7 <+35>: mov eax,DWORD PTR [ebp+0xc]
0x080484da <+38>: mov edx,DWORD PTR [eax]
0x080484dc <+40>: mov eax,0×8048620
0x080484e1 <+45>: mov DWORD PTR [esp+0x4],edx
0x080484e5 <+49>: mov DWORD PTR [esp],eax
0x080484e8 <+52>: call 0x80483bc
0x080484ed <+57>: mov DWORD PTR [esp],0×1
0x080484f4 <+64>: call 0x80483ec
0x080484f9 <+69>: lea eax,[esp+0x19]
0x080484fd <+73>: mov DWORD PTR [esp],eax
0×08048500 <+76>: call 0x80483ac
0×08048505 <+81>: mov edx,eax
0×08048507 <+83>: mov eax,DWORD PTR [ebp+0xc]
0x0804850a <+86>: add eax,0×4
0x0804850d <+89>: mov eax,DWORD PTR [eax]
0x0804850f <+91>: mov DWORD PTR [esp+0x8],edx
0×08048513 <+95>: lea edx,[esp+0x19]
0×08048517 <+99>: mov DWORD PTR [esp+0x4],edx
0x0804851b <+103>: mov DWORD PTR [esp],eax
0x0804851e <+106>: call 0x80483dc
0×08048523 <+111>: test eax,eax
0×08048525 <+113>: je 0x804853f
0×08048527 <+115>: mov DWORD PTR [esp],0×8048636
[...]

Now I will place a breakpoint exactly on the address of this call instruction.

(gdb) b *0x0804851e
Breakpoint 1 at 0x804851e

Remember to use the asterisk (*) right in front of the address, so gdb understands what follows isn’t a literal.

Why did I do it this way? Think about it the other way. What happens when the call instruction is executed? The whole stack frame stup parafernalia, namely

  • EIP is pushed to the stack (by the call itself)
  • The function prologue is executed, that is
  • the current value of EBP is pushed to the stack (from now on, known as SFP)
  • the current value of ESP passes to be the new EBP (“a new stack frame starts here”)
  • a value is subtracted from ESP (to allocate space for local variables)

That is too messy to keep track of, so if we stop the execution flow right before the call instruction, what we have is the stack right before all this stuff… the function arguments at the top of the stack ;)

(gdb) run AAAAAA
Starting program: /home/carlos/Dropbox/hacking/wargames/pass_cli AAAAAA

Breakpoint 1, 0x0804851e in main () <--- breakpoint is hit
(gdb) info reg
eax 0xbffff620 -1073744352
ecx 0x6 6
edx 0xbffff3c9 -1073744951
ebx 0x283ff4 2637812
esp 0xbffff3b0 0xbffff3b0 <--- "top" of the stack
ebp 0xbffff3d8 0xbffff3d8
esi 0x0 0
edi 0x0 0
eip 0x804851e 0x804851e
eflags 0×286 [ PF SF IF ]
cs 0×73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0×0 0
gs 0×33 51

Let’s examine the top of the stack. We are actually interested in the first three words.

(gdb) x/12x $esp
0xbffff3b0: 0xbffff620 0xbffff3c9 0×00000006 0xbffff3d8
0xbffff3c0: 0x0015d4a5 0x0011e0c0 0x6d6f797b 0x00616d61
0xbffff3d0: 0×08048570 0×00000000 0xbffff458 0x00144bd6

Without further inspection we can see a 6, the number of char the function has to compare. It looks good at least ;) Let’s remember the exact syntaxis of strncmp()

carlos@dell:~/Dropbox/hacking/wargames$ man 3 strncmp

[...]

SYNOPSIS
#include

int strcmp(const char *s1, const char *s2);

int strncmp(const char *s1, const char *s2, size_t n); <--- allright, three arguments...

[...]

Also one of the first two words must be a pointer to the hardcoded password, the other a pointer to the user input (argv[1] in this case)

(gdb) x/4x 0xbffff620
0xbffff620: 0×41414141 0x4f004141 0×54494252 0x434f535f

Well, this is pretty clearly our string of 6 “A’s” null-terminated. The other address must be the location of our password!

(gdb) x/4x 0xbffff3c9
0xbffff3c9: 0x616d6f79 0×7000616d 0×00080485 0×58000000

OK, another string of 6 characters, null-terminated. The ASCII char associated to these values can be displayed in gdb as follows:

(gdb) p/c *0xbffff3c9
$16 = 121 ‘y
(gdb) p/c *0xbffff3ca
$17 = 111 ‘o
(gdb) p/c *0xbffff3cb
$18 = 109 ‘m
(gdb) p/c *0xbffff3cc
$19 = 97 ‘a
(gdb) p/c *0xbffff3cd
$20 = 109 ‘m
(gdb) p/c *0xbffff3ce
$21 = 97 ‘a
(gdb) p/c *0xbffff3cf
$22 = 0 ‘\000

So here’s the magic password! YOMAMA! ;)

My Wii is more intelligent than me

Today I was thinking about playing with my Wii in a different way but finally it was me who was played :)

I wanted to intercept the connection my Wii establishes with the Nintendo server and modify the news stream so I could modify the headlines and show off in front of my girlfriend. Things you do a rainy Sunday afternoon…

First step: ARP poison both the Wii and the router to sniff the traffic.

root@bt:~# ettercap -T -q -i eth0 -M arp /192.168.1.1/ /192.168.1.254/

ettercap NG-0.7.3 copyright 2001-2004 ALoR & NaGA

Listening on eth0… (Ethernet)

eth0 ->       2A:04:73:94:A6:0A      192.168.1.10     255.255.255.0

Privileges dropped to UID 65534 GID 65534…

28 plugins
39 protocol dissectors
53 ports monitored
7587 mac vendor fingerprint
1698 tcp OS fingerprint
2183 known services

Scanning for merged targets (2 hosts)…

* |==================================================>| 100.00 %

2 hosts added to the hosts list…

ARP poisoning victims:

GROUP 1 : 192.168.1.254 E8:4E:CE:10:6D:E6

GROUP 2 : 192.168.1.1 00:23:69:2F:C1:61
Starting Unified sniffing…

[...]

root@bt:~# tcpdump -i eth0 -nvX -s 0 -w wii.dmp host 192.168.1.254
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes

[...]

Unfortunately all we get is a lot of HTTPS traffic (TLS v1 encrypted). Well I didn’t think that the Wii was going to send everything unecncrypted, did I? …

Next thought was to modify the attack in order to sniff the contents of the TLS session. Ettercap itself is able to perform this kind of SSL-man-in-the-middle attack.

From the ettercap man page:

SSL MITM ATTACK
       While performing the SSL mitm attack, ettercap substitutes the real ssl
       certificate with its own. The fake certificate is created  on  the  fly
       and  all  the fields are filled according to the real cert presented by
       the server. Only the issuer is modified and signed with the private key
       contained  in  the 'etter.sll.crt' file. If you want to use a different
       private key you have to regenerate this file.

This way, the attacking machine starts two SSL connections:

1. One with the server. This is a normal SSL connection, where we act as a client and use the public key presented in the server’s certificate to encrypt the data.

2. One with the client, where we impersonate the server using a fake (almost identical) certificate.

root@bt:~# ettercap -Tq -M arp:remote,oneway /192.168.1.254/ /192.168.1.1/

ettercap NG-0.7.3 copyright 2001-2004 ALoR & NaGA

Listening on eth0… (Ethernet)

eth0 -> 2A:04:73:94:A6:0A 192.168.1.10 255.255.255.0

Privileges dropped to UID 65534 GID 65534…

28 plugins
39 protocol dissectors
53 ports monitored
7587 mac vendor fingerprint
1698 tcp OS fingerprint
2183 known services

Scanning for merged targets (2 hosts)…

* |==================================================>| 100.00 %

2 hosts added to the hosts list…

ARP poisoning victims:

GROUP 1 : 192.168.1.254 E8:4E:CE:10:6D:E6

GROUP 2 : 192.168.1.1 00:23:69:2F:C1:61
Starting Unified sniffing…

This trick usually works with humans because… well, because certificates and all this technology is a fucked up system and we are so used to invalid certificates and to click “Ok”.

But my Wii is more intelligent than me and must somehow check the fingerprint of the public key in the certificate. Everything I got was a error message on my TV explaining that the connection had failed :(

The traffic capture was of course way more verbose, you can see in the capture below how I present the fake certificate and my Wii answers with a Certificate Unknown error message (click to enlarge)

Bottom line, I couldn’t play but I’m happy the security of my Wii is taken seriously.

Thumbs up Nintendo!

A short one.

Metasploit has reached 3.4.0 (stable) and it looks like it’s not going to stop here!

Thanks to the support from Rapid7, MSF has already reached more than 550 exploits and 200 auxiliary modules. Remember that apart from the script-kiddie mode (fire [an exploit] and forget), Metasploit is a great tool that assists in exploit development and much more.

I’m excited to see what this project brings in the future…

Let the botnets come to me…

A week ago I decided to install a honeypot at home in order to get some malware samples running in the wild.
I used nepenthes as recommended by the shadowserver foundation and I found it’s extremely straightforward to install and has a very small footprint. Check this uptime and load info:

root@bt:/mnt/sdcard/nepenthes/binaries# uptime
13:30:04 up 7 days, 14:15, 1 user, load average: 0.08, 0.02, 0.01

I hadn’t time yet to properly configure it but the default install captures the binaries send to the different ports (imitating a service) by the worms and store them for later analysis. After a week I have captured 66 different samples already. Not bad…

root@bt:/mnt/sdcard/nepenthes/binaries# ls -l | grep -v total | wc -l
66

A remarkable feature is the automatic send of the binaries to an online sandbox, where they will be executed and analyzed.

I will be giving a talk in November at Backtrack Day 2010 (Germany) about reverse engineering Malware. Now I just need to check my binaries directory and find a good sample for it!

I have been recently watching, dissecting actually, these videos from the Polytechnic Institute of the University of NY (cool name, eh?). These are part of the Master’s program in Cybersecurity and the people giving the talks are top of the top. Definitely worth it to check them out! (Would they count as continuing education? ;) )

As an example, an introduction to reverse engineering by Aaron Portnoy of TippingPoint.

Prepare yourself to use the pause button a lot!

Reverse Engineering 101 from Dan Guido on Vimeo.

More info on pentest.cryptocity.net

Last week I was in Barcelona helping some colleagues when a client called asking for a list of “running” clients in his network. We had a VPN connection to this net and the customer itself said that “it didn’t need an accurate list, just to have an idea” so we agreed that a simple ICMP scan would be enough.

This looked like the perfect ocassion to show off my Nmap-fu and I started my Backtrack 4 virtual machine. “Don’t worry, I’ll do a simple NMAP Ping scan…”

# nmap -sP 192.168.x.x/24

To my surprise (and shame) every single IP Address appeared listed as “UP“.

FAIL.

“This can’t be. Hmmm… Do this customer have any kind of IPS/IDS solution in place?”

“Quite probably…”

My first thought was that some kind of IPS recognized the “Ping sweep” and was answering on behalf of the clients, saying all of them are up. Security by obscurity…

I tried it again at a lower pace, using the -T Nmap parameter but I got the same results. Apparently this had something to do with some packet characteristics.

At the end we used a small windows program, Angry IP Scanner, which worked like a charm.

We didn’t have neither enough info about the network infrastructure from this customer nor time to research this funny behaviour but once back in Munich I started to play with Snort and Nmap.

Snort detects this type of scan from Nmap. Here’s an excerpt of the rule:

@ snort – icmp.rules:

alert icmp $EXTERNAL_NET any -> $HOME_NET any (msg:"ICMP PING NMAP"; dsize:0; itype:8; reference:arachnids,162; classtype:attempted-recon; sid:469; rev:3;)

Let’s see this in action.

Note: The parameter “–send-ip” specifies that I don’t want to use ARP queries as host detection method.
@ BT4 – Nmap PING sweep

root@bt:~# nmap -v -n -sP –send-ip 192.168.88.139

Starting Nmap 5.21 ( http://nmap.org ) at 2010-04-04 08:34 EDT
Initiating Ping Scan at 08:34
Scanning 192.168.88.139 [4 ports]
Completed Ping Scan at 08:34, 0.00s elapsed (1 total hosts)
Nmap scan report for 192.168.88.139
Host is up (0.0018s latency).
MAC Address: 00:0C:29:80:BB:D4 (VMware)
Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 0.07 seconds
Raw packets sent: 4 (152B) | Rcvd: 1 (28B)

root@ubuntu:~# tail -f /var/log/snort/alert

[...]

[**] [1:469:3] ICMP PING NMAP [**]
[Classification: Attempted Information Leak] [Priority: 2]
04/04-05:34:47.622963 192.168.88.132 -> 192.168.88.139
ICMP TTL:50 TOS:0x0 ID:3270 IpLen:20 DgmLen:28
Type:8  Code:0  ID:6629   Seq:0  ECHO
[Xref => http://www.whitehats.com/info/IDS162]

I captured the icmp packets from Nmap with tcpdump and it confirmed my suspicion: ICMP ECHO packets sent from Nmap have a null data section :)

This is not cool (evident signature) and I thought that even when probably there was a parameter to avoid this behaviour, it would be nice to override this in the code. So I started diving into NMAP *complex* code… here is what I found.

——– Carlos in Nmap Land ———–

@ targets.cc (massping)

static void massping(Target *hostbatch[], int num_hosts, struct scan_lists *ports) {
[...]

ultra_scan(targets, ports, PING_SCAN, &group_to);
}

@ scan_engine.cc

void ultra_scan(vector<Target *> &Targets, struct scan_lists *ports, … ) {
[...]

doAnyPings(USI);

}

doAnyPings – calls sendPingProbe(USI, hss)

3347 static void sendPingProbe(UltraScanInfo *USI, HostScanStats *hss) {
3348   if (o.debugging > 1) {
3349     char tmpbuf[64];
3350     log_write(LOG_PLAIN, “Ultrascan PING SENT to %s [%s]\n”, hss->target->targetipstr(),
3351               probespec2ascii(&hss->target->pingprobe, tmpbuf, sizeof(tmpbuf)));
3352   }
3353   if (hss->target->pingprobe.type == PS_CONNECTTCP) {
3354     sendConnectScanProbe(USI, hss, hss->target->pingprobe.pd.tcp.dport, 0,
3355                          hss->nextPingSeq(true));
3356   } else if (hss->target->pingprobe.type == PS_TCP || hss->target->pingprobe.type == PS_UDP
3357     || hss->target->pingprobe.type == PS_SCTP || hss->target->pingprobe.type == PS_PROTO
3358     || hss->target->pingprobe.type == PS_ICMP) {
3359     sendIPScanProbe(USI, hss, &hss->target->pingprobe, 0, hss->nextPingSeq(true));   <—————— !!!!
3360   } else if (hss->target->pingprobe.type == PS_ARP) {
3361     sendArpScanProbe(USI, hss, 0, hss->nextPingSeq(true));
3362   } else if (USI->scantype == RPC_SCAN) {
3363     assert(0); /* TODO: fill out */

[...]
3025 static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss,
3026                             const probespec *pspec, u8 tryno, u8 pingseq) {

[...]

3224   } else if (pspec->type == PS_ICMP) {
3225     u16 icmp_ident;
3226
3227     /* Some hosts do not respond to ICMP requests if the identifier is 0. */
3228     do {
3229       icmp_ident = get_random_u16();
3230     } while (icmp_ident == 0);
3231
3232     for(decoy = 0; decoy < o.numdecoys; decoy++) {
3233       packet = build_icmp_raw(&o.decoys[decoy], hss->target->v4hostip(),
3234                               o.ttl, ipid, IP_TOS_DEFAULT, false,
3235                               o.ipoptions, o.ipoptionslen,
3236                               0, icmp_ident, pspec->pd.icmp.type, pspec->pd.icmp.code,
3237                               o.extra_payload, o.extra_payload_length,
3238                               &packetlen);

[...]

@ tcpip.h

550 u8 *build_icmp_raw(const struct in_addr *source, const struct in_addr *victim,
551                    int ttl, u16 ipid, u8 tos, bool df,
552                    u8* ipopt, int ipoptlen,
553                    u16 seq, unsigned short id, u8 ptype, u8 pcode,
554                    char *data, u16 datalen, u32 *packetlen);

@ NmapOps.h  — were the command line parameters are parsed… If I had just started here! :)

243   extra_payload_length = 0;
244   extra_payload = NULL;

It looks like this parameter is alwasy NULL (0) as long as we don’t specify a –data-length parameter.

Finally I found:

@ nmap.cc

903         o.extra_payload_length = atoi(optarg);   <—- it parses the command line argument
904         if (o.extra_payload_length < 0) {
905           fatal(“data-length must be greater than 0″);
906         } else if (o.extra_payload_length > 0) {
907           o.extra_payload = (char *) safe_malloc(o.extra_payload_length);
908           get_random_bytes(o.extra_payload, o.extra_payload_length);
909         }

So I just did a “dirty hack” to override the parsing of the parameter and set a payload size of 40 bytes even if no parameter is passed.

901         o.debugging++;
902 //      } else if (optcmp(long_options[option_index].name, “data-length”) == 0) {
903 //      o.extra_payload_length = atoi(optarg);
904         } else if (1) {
905         o.extra_payload_length = 40;
906 //      if (o.extra_payload_length < 0) {
907 //       fatal(“data-length must be greater than 0″);
908 //      } else if (o.extra_payload_length > 0) {
909           o.extra_payload = (char *) safe_malloc(o.extra_payload_length);
910           get_random_bytes(o.extra_payload, o.extra_payload_length);
911        }
912       } else if (optcmp(long_options[option_index].name, “send-eth”) == 0) {
913         o.sendpref = PACKET_SEND_ETH_STRONG;

[...]

recompile and it’s done!

And this is what happens kids, when somebody ist bored at home and without internet access :)

Just a short one. I have just got this on an email from my Web Hosting company.

+======================================+
 PHP5-Update am 16.03.2010 um 10:00 Uhr
+======================================+

Es erfolgt ein Update aller Editionen von PHP5. So wird die bisherige
LATEST-Edition 5.2.11 zur regulären und empfohlenen Edition "5-STABLE",
während die aktuelle STABLE-Edition 5.2.9 weiterhin als Vorgängerversion
"5-LEGACY" bereitstehen wird. Neu zur Verfügung steht die Version 5.2.13,
diese ersetzt die bisherige LATEST-Edition 5.2.11.

Das am Dienstag, den 16.03.2010, um ca. 10:00 Uhr erfolgende Update
erfolgt selbstverständlich vollautomatisch, es ist Ihrerseits kein
manuelles Eingreifen erforderlich.

This comes to say in a nutshell, we have this and this vulnerable PHP version and we’ll proceed to update to this one. As grateful as I am for the information, I can’t stop thinking that maybe it’s a bit too much.

Yes, I know this is intended just for customers, but anyway you never know… who your customers are :)

Powered by WordPress | Theme: Motion by 85ideas.