Cover the face of pain and straight ahead.
post @ 2025-09-24

检查程序

$ file pwn
pwn: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=e9c3e8aac19e8a6dabd60d74867b72be88fa662e, for GNU/Linux 3.2.0, not stripped

放入IDA中进行分析:

int __fastcall main(int argc, const char **argv, const char **envp)
{
_QWORD buf[4]; // [rsp+0h] [rbp-20h] BYREF

setbuf(stdin, 0);
setbuf(stdout, 0);
memset(buf, 0, sizeof(buf));
puts("Please Input your name.");
read(0, buf, 0x100u);
printf((const char *)'@ \'', (const char *)buf);
return 0;
}

在上述反汇编出的代码中,我们得知该程序分配了一个大小为20的局部栈空间用作缓冲区,接下来我们尝试阅读一下汇编代码;

push    rbp
mov rbp, rsp
sub rsp, 20h
mov rax, cs:stdin@@GLIBC_2_2_5
mov esi, 0 ; buf
mov rdi, rax ; stream
call _setbuf
mov rax, cs:stdout@@GLIBC_2_2_5
mov esi, 0 ; buf
mov rdi, rax ; stream
call _setbuf
mov [rbp+buf], 0
mov [rbp+var_18], 0
mov [rbp+var_10], 0
mov [rbp+var_8], 0
lea rdi, s ; "Please Input your name."
call _puts
lea rax, [rbp+buf]
mov edx, 100h ; nbytes
mov rsi, rax ; buf
mov edi, 0 ; fd
call _read
lea rax, [rbp+buf]
mov rsi, rax
lea rdi, format ; "hello %s"
mov eax, 0
call _printf
mov eax, 0
leave
retn

首先是第一行push rbp,其保存了修改前的rbp,在之后的mov rbp, rsp其设置了一个新的rbp,以下是原始的栈帧

高地址 (栈底方向,rbp 所在)
+----------------------+
| 调用者栈帧 ... |
+----------------------+
| 保存的 rbp (8 bytes) | <-- rbp 指向这里
+----------------------+
| 返回地址 (8 bytes) | <-- rbp + 8 (覆盖这里可以控制程序流)
+----------------------+
| 可能的对齐或未使用 |
+----------------------+
| var_8 (rbp - 8) | 初始 0
+----------------------+
| var_10 (rbp - 0x10) | 初始 0
+----------------------+
| var_18 (rbp - 0x18) | 初始 0
+----------------------+
| buf (rbp - 0x20) | 初始 0,read 读取的数据从这里开始存放
+----------------------+ <-- rsp 指向这里(分配局部变量后)
低地址 (栈顶方向)

当程序执行后rbp被保存并设置了一个新的,那么修改后的栈布局如下:

高地址
+----------------------+
| 调用者栈帧 ... |
+----------------------+
| 返回地址 (8 bytes) | <-- rbp + 8
+----------------------+
| 保存的 rbp (8 bytes) | <-- rbp 指向这里
+----------------------+
| var_8 (rbp - 8) | 初始 0
+----------------------+
| var_10 (rbp - 0x10) | 初始 0
+----------------------+
| var_18 (rbp - 0x18) | 初始 0
+----------------------+
| buf (rbp - 0x20) | 初始 0 <-- rsp 指向这里
+----------------------+
低地址
Read More
post @ 2025-09-24

检查文件

pwndbg> checksec
File: /home/zhailin/CTF_Challenges/Pwn/BUGKU/overflow/pwn2
Arch: amd64
RELRO: Partial RELRO
Stack: No canary found
NX: NX unknown - GNU_STACK missing
PIE: No PIE (0x400000)
Stack: Executable
RWX: Has RWX segments
Stripped: No

放入IDA Pro中

int __fastcall main(int argc, const char **argv, const char **envp)
{
_BYTE s[48]; // [rsp+0h] [rbp-30h] BYREF

memset(s, 0, sizeof(s));
setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 1, 0);
puts("say something?");
read(0, s, 0x100u);
puts("oh,that's so boring!");
return 0;
}

主函数中定义了一个char类型数组s,首先,memset()函数将char类型数组s的前0x30字节初始化为0,之后,read()函数以s作为缓存区读取了0x100个字节的数据

我们继续在IDA中寻找,发现存在一个get_shell_()函数,地址为0x400751函数的返回值使用system()函数执行了cat flag命令,这样可以直接得到flag

images

这样我们就有了思路:输入0x30个字节的数据覆盖s,再输入8个字节的数据覆盖栈底指针rbp,然后将返回值修改为get_shell_()函数的地址

或者一个更直接的思路,我们在pwndbg中调试,先生成一个长度为200的随机字符串,然后将程序run起来

images

Read More

0x01.基础指令

详见:https://zz-zz-955.github.io/hugo-dev/p/gdb%E5%8A%A8%E6%80%81%E8%B0%83%E8%AF%95%E5%B7%A5%E5%85%B7%E4%BD%BF%E7%94%A8%E4%BD%BF%E7%94%A8pwndbg%E6%8F%92%E4%BB%B6/

0x02.使用gdb调试ret2text

$ file vuln
vuln: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=321b931a0d7856bf5bba57b9ceb0c0fcc1ed737b, for GNU/Linux 3.2.0, not stripped

看到是32位可执行文件,用IDA进行静态调试。

在伪代码中查看vuln函数内容。

int vuln()
{
char s[68]; // [esp+0h] [ebp-48h] BYREF

puts("There is something amazing here, do you know anything?");
gets(s);
return printf("Maybe I will tell you next time !");
}

从中得知漏洞由gets函数触发,现在我们进gdb中进行调试。

反汇编 vulnerable 函数,看看它的结构。

Read More
post @ 2025-08-28

代数系统和近世代数

概念

一个集合中,如果有一种或多种代数运算 (Algebraic Operation),则称该集合为代数系统 (Algebraic System),也称作代数结构 (Algebraic Structure)

代数学作为一个不断进步与完善的数学分支,其研究范围也从古典的整数、有理数、实数与复数等常见数集扩展到了矢量、矩阵和线性算子等对象,这类课题就共同组成了如今的近世代数 (Modern Algebra)

上文提到的代数运算,是定义在集合中的元素之间的法则,亦与集合是否能作成代数系统有着密切关联,它们扩展自常见的加减乘除这样的运算。经过定义合适的代数运算,集合可以作成群、环、域、格等代数系统

前置知识

  • $∅$:空集
  • $∀$:所有(每一个),强调普遍性
  • $∃$:存在(至少一个)
  • $∈$:属于
  • $e$:群的单位元(群中那个与任何元素运算后都“保持该元素不变”的独一无二的元素)
  • $∘$:二元代数运算
  • $ψ$:连接两个群(G 和 H)的那个特定映射(函数),在本文中无深意无需纠结

给定一个集合 $G≠∅$ 以及其上的二元代数运算$「 ∘ 」$,如若它们满足如下性质:

  1. 封闭性(Closure):∀v,u∈G,v∘u∈G;
  2. 结合律(Associativity): ∀v,u,w∈G,(v∘u)∘w=v∘(u∘w);
  3. 单位元(Identity): ∃e∈G,∀v∈G,e∘v=v;
  4. 逆元(Inverse,亦称反元): ∀v∈G,∃v−1∈G,v−1∘v=e;
Read More
post @ 2025-08-26

Analysis

查看文件类型

~/CTF_Challenges/Reverse/CatFly$ file CatFly 
CatFly: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=d05baf98f7d937f503c87ced28e78998e8d3046b, for GNU/Linux 3.2.0, stripped

main函数IDA伪代码如下:

__int64 __fastcall main(int a1, char **a2, char **a3)
{
size_t v3; // rbx
_WORD v5[4]; // [rsp+10h] [rbp-4B0h] BYREF
time_t time1; // [rsp+18h] [rbp-4A8h] BYREF
time_t timer; // [rsp+20h] [rbp-4A0h] BYREF
int longind; // [rsp+2Ch] [rbp-494h] BYREF
_QWORD s[129]; // [rsp+30h] [rbp-490h] BYREF
int v10; // [rsp+43Ch] [rbp-84h]
double v11; // [rsp+440h] [rbp-80h]
char *v12; // [rsp+448h] [rbp-78h]
int v13; // [rsp+450h] [rbp-70h]
unsigned int v14; // [rsp+454h] [rbp-6Ch]
unsigned __int8 v15; // [rsp+45Ah] [rbp-66h]
char v16; // [rsp+45Bh] [rbp-65h]
int n; // [rsp+45Ch] [rbp-64h]
int v18; // [rsp+460h] [rbp-60h]
char v19; // [rsp+467h] [rbp-59h]
int m; // [rsp+468h] [rbp-58h]
int k; // [rsp+46Ch] [rbp-54h]
char v22; // [rsp+473h] [rbp-4Dh]
int v23; // [rsp+474h] [rbp-4Ch]
unsigned __int64 v24; // [rsp+478h] [rbp-48h]
int v25; // [rsp+484h] [rbp-3Ch]
int v26; // [rsp+488h] [rbp-38h]
int v27; // [rsp+48Ch] [rbp-34h]
char v28; // [rsp+490h] [rbp-30h]
bool v29; // [rsp+491h] [rbp-2Fh]
unsigned __int16 v30; // [rsp+492h] [rbp-2Eh]
int v31; // [rsp+494h] [rbp-2Ch]
unsigned int v32; // [rsp+498h] [rbp-28h]
unsigned int i; // [rsp+49Ch] [rbp-24h]
int v34; // [rsp+4A0h] [rbp-20h]
unsigned int j; // [rsp+4A4h] [rbp-1Ch]
char *haystack; // [rsp+4A8h] [rbp-18h]

haystack = 0;
i = 0;
v32 = 0;
v31 = 0;
memset(s, 0, 1024);
v30 = 0;
v29 = 0;
v28 = 0;
v27 = 90;
while ( 1 )
{
v26 = getopt_long(a1, a2, "eshiItnd:f:r:R:c:C:W:H:", &longopts, &longind);
if ( v26 == -1 )
break;
if ( !v26 && !*((_QWORD *)&longopts.flag + 4 * longind) )
v26 = *(&longopts.val + 8 * longind);
switch ( v26 )
{
case 'C':
dword_E1F8 = atoi(optarg);
break;
case 'H':
dword_E1EC = (64 - atoi(optarg)) / 2;
dword_E1F0 = (atoi(optarg) + 64) / 2;
break;
case 'I':
v28 = 1;
break;
case 'R':
dword_E1F0 = atoi(optarg);
break;
case 'W':
dword_E1F4 = (64 - atoi(optarg)) / 2;
dword_E1F8 = (atoi(optarg) + 64) / 2;
break;
case 'c':
dword_E1F4 = atoi(optarg);
break;
case 'd':
if ( atoi(optarg) > 9 && atoi(optarg) <= 1000 )
v27 = atoi(optarg);
break;
case 'e':
dword_E104 = 0;
break;
case 'f':
dword_104C4 = atoi(optarg);
break;
case 'h':
sub_67F0(a2);
exit(0);
case 'i':
v29 = 1;
break;
case 'r':
dword_E1EC = atoi(optarg);
break;
case 's':
dword_E108 = 0;
break;
case 't':
dword_104C0 = 1;
break;
default:
continue;
}
}
if ( dword_104C0 )
{
v29 = v28 == 0;
sub_6669();
for ( i = 0; i <= 0xFF; ++i )
{
if ( *((_BYTE *)&unk_104E0 + i) )
{
sub_66AF(*((unsigned __int8 *)&unk_104E0 + i), i);
fflush(stdout);
}
}
for ( i = 0; i <= 0xFF; ++i )
{
if ( *((_BYTE *)&unk_105E0 + i) )
{
sub_66AF(*((unsigned __int8 *)&unk_105E0 + i), i);
fflush(stdout);
}
}
signal(14, sub_64C0);
if ( !_setjmp(env) )
{
alarm(1u);
while ( !feof(stdin) && v32 <= 1 )
{
v16 = getchar();
v15 = 0;
if ( v16 == -1 )
{
v16 = getchar();
switch ( v16 )
{
case -16:
v31 = 0;
if ( LOBYTE(s[0]) == 24 )
{
alarm(2u);
haystack = strndup((const char *)s + 2, 0x3FEu);
++v32;
}
else if ( LOBYTE(s[0]) == 31 )
{
alarm(2u);
dword_E1FC = (BYTE1(s[0]) << 8) | BYTE2(s[0]);
dword_E200 = (BYTE3(s[0]) << 8) | BYTE4(s[0]);
++v32;
}
break;
case -15:
sub_66AF(241, 0);
fflush(stdout);
break;
case -6:
v31 = 1;
v30 = 0;
memset(s, 0, 0x400u);
break;
case -5:
case -4:
v15 = getchar();
if ( !*((_BYTE *)&unk_105E0 + v15) )
*((_BYTE *)&unk_105E0 + v15) = -4;
sub_66AF(*((unsigned __int8 *)&unk_105E0 + v15), v15);
fflush(stdout);
if ( v16 == -5 && v15 == 24 )
{
printf("%c%c%c%c%c%c", 255, 250, 24, 1, 255, 240);
fflush(stdout);
}
break;
case -3:
case -2:
v15 = getchar();
if ( !*((_BYTE *)&unk_104E0 + v15) )
*((_BYTE *)&unk_104E0 + v15) = -2;
sub_66AF(*((unsigned __int8 *)&unk_104E0 + v15), v15);
fflush(stdout);
break;
case -1:
v32 = 2;
break;
default:
continue;
}
}
else if ( v31 && v30 <= 0x3FEu )
{
*((_BYTE *)s + v30++) = v16;
}
}
}
alarm(0);
}
else
{
haystack = getenv("TERM");
ioctl(0, 0x5413u, v5);
dword_E1FC = v5[1];
dword_E200 = v5[0];
}
v34 = 2;
if ( haystack )
{
for ( j = 0; ; ++j )
{
v3 = j;
if ( v3 >= strlen(haystack) )
break;
haystack[j] = tolower(haystack[j]);
}
if ( strstr(haystack, "xterm") )
{
v34 = 1;
}
else if ( strstr(haystack, "toaru") )
{
v34 = 1;
}
else if ( strstr(haystack, "linux") )
{
v34 = 3;
}
else if ( strstr(haystack, "vtnt") )
{
v34 = 5;
}
else if ( strstr(haystack, "cygwin") )
{
v34 = 5;
}
else if ( strstr(haystack, "vt220") )
{
v34 = 6;
}
else if ( strstr(haystack, "fallback") )
{
v34 = 4;
}
else if ( strstr(haystack, "rxvt-256color") )
{
v34 = 1;
}
else if ( strstr(haystack, "rxvt") )
{
v34 = 3;
}
else if ( strstr(haystack, "vt100") && dword_E1FC == 40 )
{
v34 = 7;
}
else if ( !strncmp(haystack, "st", 2u) )
{
v34 = 1;
}
}
v25 = 0;
signal(2, sub_64A8);
signal(13, sub_64E6);
if ( !dword_104C0 )
signal(28, handler);
switch ( v34 )
{
case 1:
qword_FE20 = (__int64)"\x1B[48;5;17m";
qword_FE30 = (__int64)"\x1B[48;5;231m";
qword_FDF8 = (__int64)"\x1B[48;5;16m";
qword_FEC0 = (__int64)"\x1B[48;5;230m";
qword_FDE0 = (__int64)"\x1B[48;5;175m";
qword_FE28 = (__int64)"\x1B[48;5;162m";
qword_FEB0 = (__int64)"\x1B[48;5;196m";
qword_FDF0 = (__int64)"\x1B[48;5;214m";
qword_FE18 = (__int64)"\x1B[48;5;226m";
qword_FDD8 = (__int64)"\x1B[48;5;118m";
qword_FEA8 = (__int64)"\x1B[48;5;33m";
qword_FE98 = (__int64)"\x1B[48;5;19m";
qword_FE10 = (__int64)"\x1B[48;5;240m";
qword_FDE8 = (__int64)"\x1B[48;5;175m";
break;
case 2:
qword_FE20 = (__int64)"\x1B[104m";
qword_FE30 = (__int64)"\x1B[107m";
qword_FDF8 = (__int64)"\x1B[40m";
qword_FEC0 = (__int64)"\x1B[47m";
qword_FDE0 = (__int64)"\x1B[105m";
qword_FE28 = (__int64)"\x1B[101m";
qword_FEB0 = (__int64)"\x1B[101m";
qword_FDF0 = (__int64)"\x1B[43m";
qword_FE18 = (__int64)"\x1B[103m";
qword_FDD8 = (__int64)"\x1B[102m";
qword_FEA8 = (__int64)"\x1B[104m";
qword_FE98 = (__int64)"\x1B[44m";
qword_FE10 = (__int64)"\x1B[100m";
qword_FDE8 = (__int64)"\x1B[105m";
break;
case 3:
qword_FE20 = (__int64)"\x1B[25;44m";
qword_FE30 = (__int64)"\x1B[5;47m";
qword_FDF8 = (__int64)"\x1B[25;40m";
qword_FEC0 = (__int64)"\x1B[5;47m";
qword_FDE0 = (__int64)"\x1B[5;45m";
qword_FE28 = (__int64)"\x1B[5;41m";
qword_FEB0 = (__int64)"\x1B[5;41m";
qword_FDF0 = (__int64)"\x1B[25;43m";
qword_FE18 = (__int64)"\x1B[5;43m";
qword_FDD8 = (__int64)"\x1B[5;42m";
qword_FEA8 = (__int64)"\x1B[25;44m";
qword_FE98 = (__int64)"\x1B[5;44m";
qword_FE10 = (__int64)"\x1B[5;40m";
qword_FDE8 = (__int64)"\x1B[5;45m";
break;
case 4:
qword_FE20 = (__int64)"\x1B[0;34;44m";
qword_FE30 = (__int64)"\x1B[1;37;47m";
qword_FDF8 = (__int64)"\x1B[0;30;40m";
qword_FEC0 = (__int64)"\x1B[1;37;47m";
qword_FDE0 = (__int64)"\x1B[1;35;45m";
qword_FE28 = (__int64)"\x1B[1;31;41m";
qword_FEB0 = (__int64)"\x1B[1;31;41m";
qword_FDF0 = (__int64)"\x1B[0;33;43m";
qword_FE18 = (__int64)"\x1B[1;33;43m";
qword_FDD8 = (__int64)"\x1B[1;32;42m";
qword_FEA8 = (__int64)"\x1B[1;34;44m";
qword_FE98 = (__int64)"\x1B[0;34;44m";
qword_FE10 = (__int64)"\x1B[1;30;40m";
qword_FDE8 = (__int64)"\x1B[1;35;45m";
off_FA88 = (char *)&unk_BCFF;
break;
case 5:
qword_FE20 = (__int64)"\x1B[0;34;44m";
qword_FE30 = (__int64)"\x1B[1;37;47m";
qword_FDF8 = (__int64)"\x1B[0;30;40m";
qword_FEC0 = (__int64)"\x1B[1;37;47m";
qword_FDE0 = (__int64)"\x1B[1;35;45m";
qword_FE28 = (__int64)"\x1B[1;31;41m";
qword_FEB0 = (__int64)"\x1B[1;31;41m";
qword_FDF0 = (__int64)"\x1B[0;33;43m";
qword_FE18 = (__int64)"\x1B[1;33;43m";
qword_FDD8 = (__int64)"\x1B[1;32;42m";
qword_FEA8 = (__int64)"\x1B[1;34;44m";
qword_FE98 = (__int64)"\x1B[0;34;44m";
qword_FE10 = (__int64)"\x1B[1;30;40m";
qword_FDE8 = (__int64)"\x1B[1;35;45m";
off_FA88 = (char *)&unk_BD06;
break;
case 6:
qword_FE20 = (__int64)&unk_BD09;
qword_FE30 = (__int64)&unk_BD0C;
qword_FDF8 = (__int64)" ";
qword_FEC0 = (__int64)&unk_BD0F;
qword_FDE0 = (__int64)&unk_BD12;
qword_FE28 = (__int64)&unk_BD15;
qword_FEB0 = (__int64)&unk_BD0F;
qword_FDF0 = (__int64)&unk_BD18;
qword_FE18 = (__int64)&unk_BD1B;
qword_FDD8 = (__int64)&unk_BD1E;
qword_FEA8 = (__int64)&unk_BD21;
qword_FE98 = (__int64)&unk_BD24;
qword_FE10 = (__int64)&unk_BD27;
qword_FDE8 = (__int64)&unk_BD2A;
v25 = 1;
break;
case 7:
qword_FE20 = (__int64)&unk_BD2D;
qword_FE30 = (__int64)&unk_BD2F;
qword_FDF8 = (__int64)&unk_BD31;
qword_FEC0 = (__int64)&unk_BD33;
qword_FDE0 = (__int64)&unk_BD35;
qword_FE28 = (__int64)&unk_BD37;
qword_FEB0 = (__int64)&unk_BD33;
qword_FDF0 = (__int64)&unk_BD39;
qword_FE18 = (__int64)&unk_BD3B;
qword_FDD8 = (__int64)&unk_BD3D;
qword_FEA8 = (__int64)&unk_BD3F;
qword_FE98 = (__int64)&unk_BD41;
qword_FE10 = (__int64)&unk_BD43;
qword_FDE8 = (__int64)&unk_BD45;
v25 = 1;
dword_E1FC = 40;
break;
default:
break;
}
if ( dword_E1F4 == dword_E1F8 )
{
dword_E1F4 = (dword_E1FC / -2 + 64) / 2;
dword_E1F8 = (dword_E1FC / 2 + 64) / 2;
byte_104CB = 1;
}
if ( dword_E1EC == dword_E1F0 )
{
dword_E1EC = (65 - dword_E200) / 2;
dword_E1F0 = (dword_E200 + 63) / 2;
byte_104CC = 1;
}
if ( dword_E108 )
{
printf("\x1BkNyanyanyanyanyanyanya...\x1B\\");
printf("\x1B]1;Nyanyanyanyanyanyanya...\a");
printf("\x1B]2;Nyanyanyanyanyanyanya...\a");
}
if ( dword_E104 )
printf("\x1B[H\x1B[2J\x1B[?25l");
else
printf("\x1B[s");
if ( v29 )
{
v14 = 5;
for ( j = 0; j < v14; ++j )
{
sub_65E2(3);
printf(" \x1B[1mNyancat Telnet Server\x1B[0m");
sub_65E2(2);
printf(" written and run by \x1B[1;32mK. Lange\x1B[1;34m @_klange\x1B[0m");
sub_65E2(2);
printf(" If things don't look right, try:");
sub_65E2(1);
printf(" TERM=fallback telnet ...");
sub_65E2(2);
printf(" Or on Windows:");
sub_65E2(1);
printf(" telnet -t vtnt ...");
sub_65E2(2);
printf(" Problems? Check the website:");
sub_65E2(1);
printf(" \x1B[1;34mhttp://nyancat.dakko.us\x1B[0m");
sub_65E2(2);
printf(" This is a telnet server, remember your escape keys!");
sub_65E2(1);
printf(" \x1B[1;31m^]quit\x1B[0m to exit");
sub_65E2(2);
printf(" Starting in %d... \n", v14 - j);
fflush(stdout);
usleep(0x61A80u);
if ( dword_E104 )
printf("\x1B[H");
else
printf("\x1B[u");
}
if ( dword_E104 )
printf("\x1B[H\x1B[2J\x1B[?25l");
}
time(&timer);
v13 = 1;
v24 = 0;
v23 = 0;
v22 = 0;
v12 = off_FA88;
while ( v13 )
{
if ( dword_E104 )
printf("\x1B[H");
else
printf("\x1B[u");
for ( k = dword_E1EC; k < dword_E1F0; ++k )
{
for ( m = dword_E1F4; m < dword_E1F8; ++m )
{
if ( k <= 23 || k > 42 || m >= 0 )
{
if ( m >= 0 && (unsigned int)k < 0x40 && m <= 63 )
{
v19 = off_FA20[v24][k][m];
off_FA88 = (char *)sub_6314((unsigned int)v24, (unsigned int)k, (unsigned int)m, v12);
}
else
{
v19 = 44;
}
}
else
{
v18 = (2 - m) % 16 / 8;
if ( ((v24 >> 1) & 1) != 0 )
v18 = 1 - v18;
s[128] = ",,>>&&&+++###==;;;,,";
v19 = asc_BFE3[v18 - 23 + k];
if ( !v19 )
v19 = 44;
}
if ( v25 )
{
printf("%s", *((const char **)&unk_FCC0 + v19));
}
else if ( v19 == v22 || !*((_QWORD *)&unk_FCC0 + v19) )
{
printf("%s", off_FA88);
}
else
{
v22 = v19;
printf("%s%s", *((const char **)&unk_FCC0 + v19), off_FA88);
}
}
sub_65E2(1);
}
if ( dword_E100 )
{
time(&time1);
v11 = difftime(time1, timer);
v10 = sub_63FF((unsigned int)(int)v11);
for ( n = (dword_E1FC - 29 - v10) / 2; n > 0; --n )
putchar(32);
dword_E1E8 += printf("\x1B[1;37mYou have nyaned for %d times!\x1B[J\x1B[0m", ++dword_108E0);
}
v22 = 0;
++v23;
if ( dword_104C4 && v23 == dword_104C4 )
sub_6471();
if ( !off_FA20[++v24] )
v24 = 0;
usleep(1000 * v27);
}
return 0;
}

注意到这一部分,printf("%s", off_FA88);这里我们进一步跟进 off_FA88
看到了对它的赋值操作 off_FA88 = sub_6314((unsigned int)v24, k, m, (__int64)v12);
此时我们查看sub_6314的源代码

if ( m >= 0 && (unsigned int)k < 0x40 && m <= 63 )
{
v19 = off_FA20[v24][k][m];
off_FA88 = (char *)sub_6314((unsigned int)v24, (unsigned int)k, (unsigned int)m, v12);
}
else
{
v19 = 44;

以下是sub_6314的代码:

char *__fastcall sub_6314(__int64 a1, int a2, int a3, __int64 a4)
{
if ( a2 != 18 )
return (char *)a4;
if ( a3 <= 4 || a3 > 54 )
return (char *)a4;
byte_104C9 = 32;
dword_E120[a3 - 5] ^= sub_62B5();
if ( (unsigned __int8)sub_62E3(dword_E120[a3 - 5]) )
byte_104C8 = dword_E120[a3 - 5] & 0x7F;
else
byte_104C8 = 32;
return &byte_104C8;
}

sub_62B5

Read More
post @ 2025-08-26

Analysis

拿到附件用IDA打开F5出伪代码

int __cdecl main(int argc, const char **argv, const char **envp)
{
char s[256]; // [esp+1Ch] [ebp-10Ch] BYREF
unsigned int v5; // [esp+11Ch] [ebp-Ch]

v5 = __readgsdword(0x14u);
puts("What is the password?");
gets(s);
if ( !strcmp(s, "the password") )
puts("FLAG:db2f62a36a018bce28e46d976e3f9864");
else
puts("Wrong!!");
return 0;
}

FLAG: flag{db2f62a36a018bce28e46d976e3f9864}

Read More
post @ 2025-08-26

Analysis

拿到附件用file确定一下文件类型得知是64位ELF文件,用IDA分析:

mian函数伪代码如下:

__int64 __fastcall main(int a1, char **a2, char **a3)
{
char s[264]; // [rsp+0h] [rbp-110h] BYREF
unsigned __int64 v5; // [rsp+108h] [rbp-8h]

v5 = __readfsqword(0x28u);
printf("Enter the password: ");
if ( !fgets(s, 255, stdin) )
return 0;
if ( (unsigned int)sub_4006FD(s) )
{
puts("Incorrect password!");
return 1;
}
else
{
puts("Nice!");
return 0;
}
}

分析上述代码我们可以得知,程序首先定义了一个长度为264位的字符出s,初步分析认为是用于存储程序的输入,往下看大致得知该程序为校验密码,跳转到验证函数sub_4006FD

验证函数伪代码如下:

__int64 __fastcall sub_4006FD(__int64 a1)
{
int i; // [rsp+14h] [rbp-24h]
_QWORD v3[4]; // [rsp+18h] [rbp-20h]

v3[0] = "Dufhbmf";
v3[1] = "pG`imos";
v3[2] = "ewUglpt";
for ( i = 0; i <= 11; ++i )
{
if ( *(char *)(v3[i % 3] + 2 * (i / 3)) - *(char *)(i + a1) != 1 )
return 1;
}
return 0;
}

Exploit

a=["Dufhbmf","pG`imos","ewUglpt"]
s=''
for i in range(12):
s+=chr(ord(a[i % 3][2 * int(i / 3)])-1)
print(s)
Read More

Cat_Jump

直接用vscode打开搜索catctf{

Caught The Flag

Miao~

附件内容是一张小猫的图片

喵~

分析图片中隐含的内容,得到一个wav文件

图二展示了使用foremost工具分析图片中隐藏文件及其结果

Audacity中打开,查看频谱图,得到密码CatCTF

图三展示了在Audacity中通过查看频谱图得到密码

Read More

附件内容:

艾尔登法环正式发售在即,迫不及待的mjj身上好像有蚂蚁在爬,写下了一句谜语:
3207357975641587136122466514425152961654613410728337142271750273124995105747053991640817066352343657398947248938255086358418100814441196784643527787764297
谜底就是flag,也是他给所有新生的祝福,希望大家享受解码的过程。

先十进制转十六进制

CTF在线工具-ASCII与进制转换|任意进制转换|ASCII、2进制、8进制、10进制、16进制

得到十六进制编码后的内容

3d3d3d3d513642475354334f4859464d37435a415450424f4454344348324d4e37434e36565a414f5a3358474859344b374b354144474e504553554355495a49

然后十六进制转字符串

字符串HEX转换

====Q6BGST3OHYFM7CZATPBODT4CH2MN7CN6VZAOZ3XGHY4K7K5ADGNPESUCUIZI

字符串反转

Read More

前置知识

JAVA序列化与反序列化简述

JAVA序列化是JAVA语言内置的一种对象持久化的机制,它可以将JAVA对象转化为字节流,以便于在网络中进行传输,或者保存到本地进行持久化(类似于PHP序列化)。反序列化则是序列化的逆过程,将字节流转化回JAVA对象。

序列化过程中,JAVA会将对象的类型、属性以及属性的值等信息一起保存下来,反序列化时,JAVA会根据这些信息重新构建出原来的对象。这就意味着,如果一个恶意用户能够控制序列化的字节流,那么他就有可能在反序列化时构造出含有恶意代码的对象,从而引发安全问题

JAVA反序列化漏洞的常见产生原因

JAVA反序列化漏洞的产生,主要是因为在反序列化时,JAVA会自动调用对象的readObject()方法,而这个方法通常是开发者自定义的,如果开发者在这个方法中执行了不安全的操作,就可能产生安全漏洞。

另一种常见的情况是,JAVA的某些内置类库,如Apache Commons Collections、JAVA RMI等,在反序列化时,会自动执行某些可以被恶意利用的方法。如果应用使用了这些类库,并且没有对反序列化的输入进行有效的限制,那么就可能产生反序列化漏洞。

常规反序列化漏洞的发现与利用技术

在实际的安全测试中,发现JAVA反序列化漏洞,通常需要通过静态代码分析、动态测试、模糊测试等手段。其中,静态代码分析是直接阅读和理解源代码,找出可能存在问题的地方;动态测试是在运行应用的过程中,对其进行观察和调试,寻找可能的漏洞;模糊测试是对应用的输入进行大量的随机化修改,试图触发未知的漏洞。

利用JAVA反序列化漏洞,通常需要构造特殊的序列化字节流,这个字节流在反序列化时,会产生恶意的效果。这需要对JAVA序列化的格式有深入的理解,同时还需要对目标应用的具体情况有足够的了解。

Read More
⬆︎TOP