Toddler's Bottle의 마지막 문제다.. 한~~참 과거에 glibc2.3.2 버전 이하에서 힙을 free() 해줄때 내부의 unlink취약점을 문제에 나타냈다. 

업데이트되고 지금은 활용할 수 없는 버그이다.


소스코드를 먼저 보겠다. 구조체와 system함수, unlink함수, gets함수 등... 으로 구성 되어 있다.



OBJ구조체가 선언 되있다. 그 내용을 보면 구조체의 포인터 fd와 bk가 있고 8바이트 크기의 버퍼로 구성 되어있다.

malloc(동적할당)함수를 이용하여 힙공간을 할당하면  구조체의 사이즈보다 더 넓은 메모리 공간이 생성된다. 그이유는

size(4바이트)와 pre_size(4바이트) 정보를 담아야하기 때문이다.  


size : 현재 chunk의 크기정보

prev_size : 이전의 chunk가 free되었을 때 그 chunk의 크기정보


OBJ구조체는 총 24바이트의 공간으로 힙에 할당 될 것이다.   


간단히 오버플로우가 일어나는 것을 확인해준다.(이유는 문자열 길이를 체크하지 않는 gets함수의 사용때문)

프로그램을 실행한뒤 'AAAA'를 입력해주고 힙내부를 봤다.


구조체의 FD BK가 A <=> B <=> C를 가르키고 있는 구조다.

size는 24바이트로 16진수로 표현하면 0x18이여야 하지만 왜 0x19일까? 이유는 하위 3비트가 플래그 용도로 사용되기 때문이다. 

1. PREV_INUSE : 이전 chunk가 사용중일때 설정되는 플래그 

2. IS_MMAPPED : mmap()함수로 할당된 chunk일 때 설정되는 플래그 

3.NON_MAIN_ARENA : 멀티쓰레드 환경에서 main이 아닌 쓰레드에서 생성된 메모리 일 때 설정되는 플래그



하지만, 다음 아래는 unlink(B)함수 실행 뒤의 힙 구조이다. C의 BK가 B대신 A를 가르킨다.



system("/bin/sh");를 주어준 것을 보아 ret을 bof로 덮어 shell을 실행 하라는 의도 같다. 어떻게 할 수 있을까?

gets(A->buf);로 덮을 수 있는 값을 구조체 B, C의 메모리 공간들이다.  


malloc된 A, B, C는 어떤 과정을 거쳐 double linked list 구조를 가지는지,

fd의 값과 bk값이 어떻게 담기게 되는지 어셈으로 알아본다. 아래와 같은 과정을 거치는 것을 알 수 있다. 


      C code to asm ------->>>>>> 



다음으로 unlink함수의 과정이다.

                               C code to asm--------->>         

1번부터 차례대로 BK=P -> bk; , FD=P -> fd; .... 라고 볼 수 있다.

1번 과정에 ebp-0x4는 BK공간이고 2번 과정에 ebp-0x8은 FD공간이라고 할 수 있다.

3번은 FD->bk=BK; 과정인데 fd+4(ebp-0x8)에 bk를 넣고 

4번 BK->fd=FD; 과정에서는 bk(ebp-0x4)에 fd를 저장하는 것을 알 수 있다.


AAAA(4) | shell()함수주소| dummy(8) | {heapleak주소+12바이트(A의 fd로부터 shell()함수주소까지 거리)+4바이트(lea esp,[ecx-4]이기 때문에)}(4) | 스택의 leak 주소+16바이트(ebp-0x4와의 거리차이)(4)(즉, C의구조체의 bk공간의 주소 = 스택의 ebp-0x4의 주소를 넣는다.) <- 이 공간엔 unlink취약점에 의해 shell함수의 주소값이 들어갈 것


[ebp-0x4]= shell()주소가 담긴 heap의 위치+4 왜+4? ecx-0x4때문에

ebp-0x4 = leak stack주소 + 거리차이(0x10)

leave = push esp, ebp + pop ebp 
ret = pop eip + jmp eip



'System Hacking > pwable.kr' 카테고리의 다른 글

18.pwnable asm  (0) 2018.02.28
17.pwnable memcpy  (0) 2018.02.28
16.pwnable uaf  (0) 2018.02.26
15.pwnable cmd2  (0) 2018.02.23
14.pwnable cmd1  (0) 2018.02.23


nc 0 9026으로 접속하면 asm프로그램이 실행될거고 문제의도에 알맞은 shellcode를 넣으면 flag가 나온다고 한다.



위와 같이 프로그램을 실행하면 

이 문제에서는 SECCOMP 샌드 박스에서 x64 쉘 코드를 실행해야 한다.

open () / read () / write () 시스템 호출만 사용하여 플래그가 나오는 쉘 코드를 만들도록하십시오. 라고 나와 있다.



stub[]= 부분을 명령어 형태로 보니 

아래와 같이 모든 레지스터를 초기화를 한다.


파일을 메모리에 대응시키기위해 mmap함수를 이용해서 메모리에 0x1000공간을 만들어준다.

그다음에 memset을 통해서 0x1000공간을 모두 NOP로 채워주고

memcpy를 이용해서 sh시작 주소에 stub[]를 채워주고 strlen(stub)를 이용해서 offset 값을 구해준다

그후에 read(0, sh+offset,  1000)을 수행하기 때문에 결국 sh에는 

stub[]+내가 넣은 쉘코드

와 같은 구조가 될 것이다.

chroot는 가상의 루트 디렉토리를 생성하므로 심볼릭 링크도 불가능하다.

그후에 sandbox함수가 실행되고

sh()이 한번 실행된다.


쉘코드를 만들어서 넣어야하는데 콜 할 수 있는 함수는 read, open, write, exit만 주어져 있다.

쉘코드를 구성해보면 아래와 같다.

pwntool을 이용하면 shellcode도 편하게 만들 수 있다..





'System Hacking > pwable.kr' 카테고리의 다른 글

19.pwnable unlink  (0) 2018.03.10
17.pwnable memcpy  (0) 2018.02.28
16.pwnable uaf  (0) 2018.02.26
15.pwnable cmd2  (0) 2018.02.23
14.pwnable cmd1  (0) 2018.02.23


쉬고가라 memcpy의 성능에 관해 작은 실험을 도와달라고 한다.

그러면 flag를 준다고..


readme 파일이 있어서 먼저 읽어 보기로 한다.



nc 0 9022에 접속하면 컴파일된 바이너리가 memcpy_pwn권한 으로 실행된다고 한다.



experiment 5 부분에 fast_memcpy : 출력 부분에서 segmentation fault가 뜬다.

소스코드 맨 윗줄 주석에 보면 //compiled with : gcc -o memcpy memcpy.c -m32 -lm

라고 컴파일 옵션을 알려준다. 


참고)


-m32 옵션 에러가 난다면  --> apt-get install gcc-multilib



우선 fast_memcpy를 보면 len값이 64보다 작다면 slow_memcpy()가 실행된다.

experiment 4까지는 입력 값이 64를 넘지 않아 slow_memcpy()가 실행되어 오류가 나지 않았지만 

experiment 5부터는 len값이 64이상이 되기 때문에 fast_memcpy()가 진행되면서 오류가 난것으로 보인다.



gdb로 seg fault부분을 보기위해 내 로컬에서 컴파일 해보기로 한다.



gdb로 코어파일을 보면

fast_memcpy+52부분에서 문제가 있는듯 하다




movdqa

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


movdqa는 정렬된 주소의 16byte 값을 이동시키는 명령어이고, movntps는 xmm 레지스터의 16byte 값을 메모리에 옮기는 명령어이다.




데이터 주소를 출력해주는 코드를 추가해서 프로그램을 다시 한번 실행 해보았다.

할당한 데이터 사이즈에 + 8byte씩 더 공간이 있다. molloc을 하면서 메모리공간에 대한 부가정보를 담는 공간이 추가로 생긴 듯 하다. +8바이트 만큼



메모리 공간이 16배수가 아닌 공간을 +8을 해줘서 16의 배수가 되도록 조정 해준다.

nc로 접속해서 값을 입력해주면 플래그가 출력된다.


 

'System Hacking > pwable.kr' 카테고리의 다른 글

19.pwnable unlink  (0) 2018.03.10
18.pwnable asm  (0) 2018.02.28
16.pwnable uaf  (0) 2018.02.26
15.pwnable cmd2  (0) 2018.02.23
14.pwnable cmd1  (0) 2018.02.23

#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;

}


User After Free


동적할당(Dynamic memory allocated) 된 heap을 free하고 다시 재사용(Dynamic memory reuse) 할 때에 취약점이 발생할 수 있다.


Deferred Coalescing (병합 지연)

malloc -> caching free된 heap이 다음에 realloc될 때에 같은 사이즈로 요청받을 수 있습니다. 이 때 heap을 병합하거나 분할하는 시간을 절약하고자 free된 heap을 남겨뒀다가 reuse할 때 그대로 쓰게 해주는 방법입니다.



         --->>>gdb--->>>>


분기문이 있고 1을 입력했을 경우를 introduce()가 실행되는 과정에서 introduce 주소의 위치를 알아야 하기 때문에 main+265에 bp를 걸고 프로그램을 실행시켜 보자.  0x400fcd로 jmp하고 차례대로 코드가 실행 될 것이다. 



코드를 보면 Human 클래스의 virtual function인 give_shell()을 호출하는 부분이 보이지 않는다하지만 같은 클래스의 객체끼리 가상함수를 모아 놓고 사용하는 개념인 vtable을 이용해 1 use에서 introcude() 호출 대신 give_shell()를 호출하도록 만든 것이다.



main+286에서 함수를 call하는데 introduce() 함수를 실행하는 부분이다.

main+272 부분에서 rax에 give_shell 함수의 주소에 +8을 해준다 이 값이 rdx로 들어가는 것을 알 수 있다.

아래와 같이 간단하게 확인해 보니까 맞다는 것을 알 수 있다.



다음으로 힙에 할당된 Man객체를 내부를 보기로 한다.

heap에 이름이 있는데 객체는 name 문자열의 포인터를 가지고 있다.



Man의 객체아래 바로 Woman의 객체도 함께 생성되어 있는 것을 볼 수 있다.



tmp/oieh/file에 "AAAA"를 써주고 프로그램을 실행 시켰다.




3 -> 2 ->1 한번만 free를 해주고 데이터를 썻더니 w->introduce()는 덮혔지만

m->introduce() 주소가 0x00000000으로 되어 프로그램 segment fault가 떠 종료된다.


그리하여 3 -> 2 -> 3 -> 2 -> 1 과 같이 두번 free와 data을 썻다.

아래와 같이 의도한 메모리 위치에 값을 넣어 줄 수 있었다.


"AAAA"문자열 대신에 0x401570(introduce함수) -0x8 = 0x401568(give_shell함수)값을 넣어주면 쉘이 실행된다. 




'System Hacking > pwable.kr' 카테고리의 다른 글

18.pwnable asm  (0) 2018.02.28
17.pwnable memcpy  (0) 2018.02.28
15.pwnable cmd2  (0) 2018.02.23
14.pwnable cmd1  (0) 2018.02.23
13.pwnable lotto  (0) 2018.02.23

이번문제에는 필터가 더 세세하게 적용되있다는 점과 모든 환경변수를 찾아서 초기화 하는 함수가 적용되어 있다.

어떻게 flag값을 읽어야 할까??


우선 환경 변수는 사용할수 없기 때문에 flag문자열 필터링을 우회 할 수 있게끔 tmp에 디렉토리를 만들고 아래와 같이 심볼릭 링크를 걸어준다.


echo명령어에 -e옵션을 붙여주면 \xnn과 같은 16진수와 \0nn과 같은 8진수를 이용해 문자를 나타내게 할 수 있다.


16진수가 편해서 아래와 같이 입력해보니..


/로 입력이 들어가지 않았다.  다음으로 8진수를 이용해본다.

-e옵션이 그대로 입력 되는 것을 볼 수 있었다.




쿼우팅 규칙에 따라서 마지막 싱글로 감싼 것이 제대로 들어갔다.


'System Hacking > pwable.kr' 카테고리의 다른 글

17.pwnable memcpy  (0) 2018.02.28
16.pwnable uaf  (0) 2018.02.26
14.pwnable cmd1  (0) 2018.02.23
13.pwnable lotto  (0) 2018.02.23
11.pwnable coin1  (0) 2018.02.23


리눅스에서 PATH 환경변수가 무엇인가? 라고 물어보고 있다.



코드를 보면 argv를 받고 envp를 받아온다.

argv 인자에 flag나 sh, tmp 와 같은 문자열이 있다면 false(0)으로 필터링을 한다.

putenv를 이용해서 PATH 환경변수를 /fuckyouverymuch로 설정한다. 그래서 명령어들은 절대경로를 사용하기로 한다.



1. 환경변수



2. 심볼릭 링크 



3. 와일드 카드





'System Hacking > pwable.kr' 카테고리의 다른 글

16.pwnable uaf  (0) 2018.02.26
15.pwnable cmd2  (0) 2018.02.23
13.pwnable lotto  (0) 2018.02.23
11.pwnable coin1  (0) 2018.02.23
10.pwnable shellshock  (0) 2018.02.22


실제 로또 방식과 같이 1~45사이의 랜덤 숫자중 6자를 모두 맞추면 flag가 출력되는 코드이다. 하지만..



밑줄친 코드를 보면 lotto[i]와 submit[j]을 차례대로 비교하지만 내가 제출한 값이 중복된 값 인지는 체크하지 않는다. 

즉, 한숫자를 6번 써 내서 랜덤값 6개 중 하나와 일치하면 1등이 되는 오류가 있다.

unsigned char형으로 bytes를 받기 때문에 아스키코드표를 참고해서 10진수로 1부터 45 사이에 문자를 넣어주면 된다.


나는 구두점 문자를 이용했다.


'System Hacking > pwable.kr' 카테고리의 다른 글

15.pwnable cmd2  (0) 2018.02.23
14.pwnable cmd1  (0) 2018.02.23
11.pwnable coin1  (0) 2018.02.23
10.pwnable shellshock  (0) 2018.02.22
07.pwnable input  (0) 2018.02.19



동전개수가 주어지고 그중에 한가지 위조동전을 찾아야한다 진짜 동전은 무게가 10이고 위조는 9이다.

C는 물어볼 수 있는 횟수인데 물어볼 수 있는 동전 개수는 제한이 없고 그 동전 무게의 합을 알려준다.

그 합으로 유추해서 위조동전이 어디에 있는지 범위를 줄여 나가면 된다.

30초 안에 100개의 위조동전을 찾아야 flag를 주기 때문에 수작업으로는 불가능 하다.

이진트리를 이용해서 쉽게 풀 수 있다.


※정답은 C횟수를 다 사용한 다음 보내줘야 서버가 맞았는지 틀렸는지 채점한다. 한마디로 주어진 C횟수보다 위조지폐를 빨리 찾아도 채점은 C만큼 send를 받은 다음 채점한다.









'System Hacking > pwable.kr' 카테고리의 다른 글

14.pwnable cmd1  (0) 2018.02.23
13.pwnable lotto  (0) 2018.02.23
10.pwnable shellshock  (0) 2018.02.22
07.pwnable input  (0) 2018.02.19
09.Pwnable mistake  (0) 2018.02.16


setresuid유저에 대한 정보를 셋팅 ,setresgid그룹에 대한 정보를 셋팅 

하는데 getegid는 현제 프로세스의 유효 그룹아이디를 가져와 인자로 사용한다.

ls -al 명령어 출력을 보면 flag 파일과 shellshock 파일의 gid가 shellshock_pwn으로 설정 되어있 다.


shellshock프로그램을 이용해서 권한을 높혀 flag를 출력하는 문제 같은데 문제 이름이 shellshock다.




위와 같이 환경변수에 변수를 추가 할 수 있다.

마찬가지로 함수를 추가 할 수 도 있는데 

형식은 아래와 같다.


그렇지만 변수에 ' '를이용해서 함수의 형식대로 변수를 만들면(속임수)

아래와 같이 환경변수에 추가가 된다.

그후에 서브쉘을 띄우면 이전에 시작하는 과정에서 환경 변수를 읽어오는데

bash는 () { 로 시작하는 변수를 함수라고 판단하게 된다. 읽어오는 과정에서 함수뒤에 있는 명령어를 만나면 실행되어 버린다.


아래 사진은 함수를 환경변수에 추가한 모습


이처럼 변수를 함수처럼 속일 수 있는데 함수처럼 생긴 변수 뒤에 ;와 명령어들을 추가하게 되면 그 명령어들까지

실행되는 취약점이 있다.


우선 아래와 같이 export와 env 명령어의 차이점부터 파악을 해보자



      <차이점>



shellshock@ubuntu:~$ env x='() { :; }; echo asd'

shellshock@ubuntu:~$ ./bash

위와 같이 서브쉘을 실행해도 아무것도 출력되지 않는다.  env는 일회용이기 때문이다.




이점을 이용하면 아래와 같은 두 가지의 답이 나온다.


shellshock@ubuntu:~$ export x='() { :; }; /home/shellshock/bash -c "cat flag";'


shellshock@ubuntu:~$ env x='() { :; }; /bin/cat flag' ./shellshock

only if I knew CVE-2014-6271 ten years ago..!!

Segmentation fault


환경변수 삭제 명령어는 unset [변수]이다.


'System Hacking > pwable.kr' 카테고리의 다른 글

13.pwnable lotto  (0) 2018.02.23
11.pwnable coin1  (0) 2018.02.23
07.pwnable input  (0) 2018.02.19
09.Pwnable mistake  (0) 2018.02.16
12.Pwnable blackjack  (0) 2018.02.16

c로 짜여진 프로그램에서 주어진 조건에 맞게 5단계에 걸쳐 올바르게 들어간다면 flag를 출력해주는 프로그램이다. 구성을 아래와 같다.

나는 pwntools를 이용한 python스크립트를 간단하게 짜서 문제를 풀었다. 


Stage 01. argv

argv['A']에 "\x00", argv['B']에 \x20\x0a\x0d"가 들어있는가?


Stage 02. stdio

파일 디스크립터 표준입출력을 이용해서 특정값(\x00\x0a\x00\xff, \x00\x0a\x02\xff)을 넣을 수 있는가?


Stage 03. env

환경변수 인풋을 넣을 수 있는가?


4.file

"\x0a"라는 파일을 열고 문자를 write할 수 있는가?


5.network

argv['C']의 값을 포트번호로 하는 

소켓통신을 통해 어떤 값을 send할 수 있는가?


아래를 참고하여 페이로드를 파악해보면 이해가 쉽다.












pwntool을 이용하면 소켓통신을 remote하나로 간편히 할 수 있고 local에 있는 프로그램에 여러 인자들을 긴 코드 필요없이 

간단히 넘겨 줄 수 있다.



'System Hacking > pwable.kr' 카테고리의 다른 글

11.pwnable coin1  (0) 2018.02.23
10.pwnable shellshock  (0) 2018.02.22
09.Pwnable mistake  (0) 2018.02.16
12.Pwnable blackjack  (0) 2018.02.16
08.Pwnable leg  (0) 2018.02.15

+ Recent posts