---
tags: CTF
---
# VietAn Web challenge 0x2 - writeup
## Analysis
```typescript=
// lib/index.ts
router.get('/', (req: IRequest, res: Response) => {
if (!req.user) return res.redirect('/auth/login');
const secret = req.user.role === Role.USER ? 'No secret for you' : process.env.FLAG;
res.render('index', {
user: req.user,
secret,
});
});
```
Biết được flag nằm ở env và account login phải có role khác USER.
```typescript=
// lib/util.ts
import { Database } from "@drstrain/database";
import { Request } from 'express';
export enum Role {
ADMIN = 0,
USER = 1,
}
export interface User {
username: string;
password: string;
role: Role;
}
const admin: User = {
username: 'admin',
password: process.env.ADMIN_PASSWORD,
role: Role.ADMIN,
}
const userDatabase = new Database();
userDatabase.set('admin', admin);
export { userDatabase };
export const sessionDatabase = new Database('session');
export interface IRequest extends Request {
user: User;
cookies: { id: string};
}
```
Khi server được run thì sẽ set 1 tài khoản admin với role là ADMIN (0) vào trong database.
```typescript=
// lib/auth.ts
type AuthBody = {
username: string;
password: string;
}
function handleLogin(body: AuthBody, res: Response): boolean {
const { username, password } = body;
const user = userDatabase.get(username);
if (!user || user.password !== password) return false;
const newSession = randomBytes(32).toString('hex');
sessionDatabase.set(newSession, user);
res.cookie('id', newSession);
return true;
}
router.post('/login', (req, res) => {
if (handleLogin(req.body, res)) return res.redirect('/'); // Success
res.render('auth', {
title: 'Login',
error: 'Wrong username or password'
});
});
function handleRegister(body: AuthBody, res: Response): boolean {
const { username, password } = body;
if (userDatabase.get(username)) return false; // User already existed
const user: User = {
username,
password,
role: Role.USER,
};
userDatabase.set(username, user);
const newSession = randomBytes(32).toString('hex');
sessionDatabase.set(newSession, user);
res.cookie('id', newSession);
return true;
}
router.post('/register', (req, res) => {
if (handleRegister(req.body, res)) return res.redirect('/'); // Success
res.render('auth', {
title: 'Register',
error: 'Something is wrong',
});
});
```
Tại dòng 38 khi router `register` được gọi thì sẽ nhận tham số từ `req.body` và đưa vào hàm `handleRegister` tại dòng 24 để xử lí.
Trong source code này, tác giả sử dụng lib của tác giả viết có tên là [@drstrain/database](https://github.com/phvietan/database).
Cụ thể khi vô source code của lib đọc thì thấy được đoạn code này có thể dùng được `__proto__` khi `namespace` rỗng.

Source: https://github.com/phvietan/database/blob/main/src/index.ts#L28-L30
<!--Tại dòng 26 của file `lib/auth.ts` mình đã để ở trên thì có sử dụng đến hàm `get` trong lib `@drstrain/database`. Vậy bây giờ trace ngược xem hàm này có nhận `namespace` vào hay không?-->
Dòng 21 ở hình dưới khai báo class `Database` với `namespace` rỗng.

=> Chúng ta có thể dùng `__proto__` như đã nói ở trên.
Request login với `username` là `_proto__`. Giá trị trả về là 1 `Object.__proto__`.

Vì `Object.__proto__` không tồn tại attribute `password` nên giá trị của `user.password` sẽ là `undefined`.
Gửi request không có tham số `password` sẽ làm cho biến `password` lấy từ `req.body` lúc này là `undefined`.

Sau khi qua được câu lệnh if, giá trị được lưu vào `sessionDatabase` sẽ là giá trị của `Object.__proto__`.
=> Lúc này `role` ở trong `req.user` là `undefined` nên có thể qua được đoạn middleware ban đầu để hiện thị flag.

## Exploit
1. Request login để lấy cookie.

2. Sử dụng cookie để truy cập vô trang chủ lấy flag.
