week1

Real Login

使用ida_pro反编译之后可以看到,在main函数中有两个函数,一个是printBanner(),还有一个是func()。

image-20241001203238481

image-20241001203251651

image-20241001203414165

主要看func()这个函数,跟进func之后可以发现,在对输入的buf进行检验之后,会执行一个win()函数,win()函数中调用了system(‘/bin/sh’),只要输入正确的password就可以通过检验。

跟进password可以发现,password是一个存在data段的字符串,’NewStar!!!’

1
2
解题过程:
使用nc连接下发的容器之后,输入NewStar!!!,按下回车之后即可getshell

image-20241001203628988

由于这个wp是面向新生向的,这里也说说怎么用nc,nc就是netcat(这个可以百度到的,搜下载就好了,在你的电脑上下载后nc之后就可以使用了)

image-20241001203956824

这里演示用的是windows主机,但是其实nc一般是下在wsl或者linux虚拟机上的,可以看到使用nc连接到这个ip和端口之后,在input后面输入NewStar!!!之后,弹出了congratulations!!,在这之后就可以执行命令了,ls是显示当前目录,cat flag是读取当前目录中的flag文件的意思。按下ctrl C之后退出连接。

game

由于main函数的结构跟上题差不多,这里就不细讲了。主要看game函数,可以看到在这个函数中有一个alarm(5u),然后再下面是一个while循环,每次输入一个1-9之间的数(即v0),然后加到v1上,如果v1>999的话,就会执行system函数,返回一个shell(shell就是一个命令行的界面)

image-20241001204535205

这道题的考点其实是对脚本的编写,因为在5秒之内(alarm的效果就是5秒内结束进程)是不可能手动发送这么多次v0的,所以需要编写脚本来解题

image-20241001205454692

这个是对game文件的检查,check.sh是我自己写的sh脚本,其实就是file和checksec两个命令而已,从返回的结果可以看到这个game文件是x86-64架构的。(其实使用ida_pro反编译的时候就知道是32位还是64位了)
x86-64可能是intel或者amd的,这里就假设是amd的吧,对于程序的架构想要有更多了解的话可以百度一下,很容易搜到的。其他的返回信息也可以自己搜索一下是什么意思,由于都跟本题没什么关系,这里就不赘述了。

1
2
3
4
5
6
7
8
9
10
from pwn import *
# 设定连接的程序的架构,操作系统和日志的精度
context(arch = 'amd64',os = 'linux',log_level = 'debug')
# 建立远程连接
p = remote('101.200.139.65',20949)
# 循环发送,满足v1的条件
for i in range(1,200):
p.sendline('9')
# 建立交互
p.interactive()

image-20241001205951416

这是在linux虚拟机上执行的结果

前面那些报错就是/bin/sh无法执行的命令,因为没有对应的命令,成功建立连接之后就可以cat flag了

overwrite

image-20241001210500402

函数结构很清晰,有一个read函数,从标准输入中读取nbytes长度的字符串存储到nbyte_4的地址上,然后对nptr进行检验,如果atoi(nptr)的结果大于114514的话就执行getflag函数。

由于nptr是没有初始化的,所以这个值理论上是无法控制的。但是在这道题中,nbytes是可控的,如果使用read函数读入长度为100的字符串会怎么样呢?

下图为func函数的栈结构,由于栈是由高位地址向低位地址增长的,如果在nbytes_4处输入超过0x30长度的字符串的话,就会覆盖到nptr的部分,也就是说,如果输入足够长度的字符串,就可以通过read函数修改nbyte_4的同时修改nptr。

image-20241001211040337

然而在本题中对nbytes又存在限制,无法输入大于48的nbytes,如果nbytes大于48的话就会结束程序,为了绕过这个限制,需要对nbytes进行研究,首先可以看到nbytes是一个int类型的整数,在进行比较时也是int类型,但是在read函数中它却变成了unsigned int的,这说明什么呢。总所周知,int类型是有符号的整数,而unsigned int是无符号的整数,也就是说,int类型中的负数在unsigned int类型中却是正数,通过这一点我们就可以对if(nbytes>48)进行绕过,只需令nbytes为-1即可。

1
2
3
解题过程:
nc连接之后,输入-1,再输入111111111111111111111111111111111111111111111111666666即可
(0x30个1和6个6,0x30是为了覆盖0x30长度的nbytes_4的区域(这个值可以通过nbytes_4和nptr之间的间隔计算出来,也就是ida_pro中的[rbp-80h]和[rbp-50h]),666666则是nptr的值)

image-20241001213217954

gdb

我去,柚子厨蒸鹅心(

不是哥们,你这题怎么看起来像逆向呢?

解题思路:跑一遍gdb,然后把执行完sub_12E5之后的s的值记录下来,再发回去就可以了。

image-20241001213821634

image-20241001220336741

可以看到s1的值为0x4557455355431d5d

1
2
3
4
5
6
7
8
9
from pwn import *
# 设定连接的程序的架构,操作系统和日志的精度
context(arch = 'amd64',os = 'linux',log_level = 'debug')
# 建立远程连接
p = remote('39.106.48.123', 31276)
# 转为64bit的值之后发过去
p.sendline(p64(0x4557455355431d5d))
# 建立交互
p.interactive()

image-20241001220617823

week2

(更新待续,因为wp貌似不能提前发,不过week1应该没事)