pwnable.kr第七八题 input leg

在这里插入图片描述

第七题 input

参考链接:

这道题可太痛苦了,好多知识点;
这里只需要按它的比较走就可以了。

解题过程
第一次比较:

在这里插入图片描述
这里只需要让输入的长度为100,并且满足argv[‘A’]、[‘B’]的值即可
答案如下:

代码如下:

#第一个参数应该是调用的函数名称
args.append('/home/input2/input')
#构建第一次判断答案
for i in range(1,100):
        args.append("a")
args[ord('A')]=""
args[ord('B')]="\x20\x0a\x0d"
第二次比较

在这里插入图片描述
read的第一个参数为fd(文件描述符),表示输入来源,可以为0、1、2,分别表示标准输入,标准输出和标准错误,输入分别来自于键盘输入,显示器,显示器。
这里可以使用os.write(fd, str)函数来进行写入,其中fd为文件描述符,str为输入的字符串,构建代码如下:

os.write(0,"\x00\x0a\x00\xff")
os.write(2,"\x00\x0a\x02\xff")
第三次比较

在这里插入图片描述
getenv函数格式如下:
char *getenv(const char *name)
表示读取name所在环境的值,因此只需要将\xde\xad\xbe\xef地址处存放的数据进行赋值即可,代码如下:

# 第三次判断答案
environ={"\xde\xad\xbe\xef":"\xca\xfe\xba\xbe"}
第四个比较

在这里插入图片描述
这里只需要打开一个文件进行写入即可:

fp=open("\x0a","wb")  #wb表示只写一个二进制文件
fp.write("\x00"*4)
fp.close()
socket函数

在讲第五次比较前先说一下socket函数

该函数的使用格式如下:
socket.socket(socket_family,socket_type,protocal=0)
其中socket_family 可以是 AF_UNIX 或 AF_INET。AF_UNIX用于同一台机器上的进程间通信,AF_INET用于IPV4协议的TCP和UDP。
socket_type 可以是 SOCK_STREAM 或 SOCK_DGRAM。分别表示流套接字和数据报文套接字。

流式套接字
使用这种套接字时,数据在客户端是顺序发送的,并且到达的顺序是一致的。比如你在客户端先发送1,再发送2,那么在服务器端的接收顺序是先接收到1,再接收到2,流式套接字是可靠的,是面向连接的;
数据报套接字
这种套接字是无连接的,数据是打包成数据包发送的,到达的顺序不一定与发送的顺序是一致的,并且数据不一定是可达的,并且接收到的数据还可能出错。

protocol 一般不填,默认值为 0。

第五个比较

在这里插入图片描述

这里直接使用socket端口连接传递数据即可,注意sd.connect指定的端口因和argc[‘C’]赋的值相同,这样才能正常连接并传递数据,这里设置为8888,构造答案如下:

args[ord('C')]="8888"
sd = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0);
time.sleep(2)#因为socket连接需要一点时间,如果没有等待很可能连接错误,没有这句话的话就得多运行一遍就好了
sd.connect(("127.0.0.1",8888))
sd.send("\xde\xad\xbe\xef")
sd.close()
答案

1、 在tmp目录下创建一个python文件并写入下面代码:

import socket
import os
import subprocess
import time

stdinr,stdinw=os.pipe()
stderr,stderw=os.pipe()

args=[]
args.append('/home/input2/input')
#构建第一次判断答案
for i in range(1,100):
        args.append("a")
args[ord('A')]=""
args[ord('B')]="\x20\x0a\x0d"

args[ord('C')]="8888"  #这里的端口和sd链接的端口应该一样

#第二次判断答案
os.write(stdinw,"\x00\x0a\x00\xff")
os.write(stderw,"\x00\x0a\x02\xff")

# 第三次判断答案
environ={"\xde\xad\xbe\xef":"\xca\xfe\xba\xbe"}

#传递参数
pro=subprocess.Popen(args,stdin=stdinr,stderr=stderr,env=environ)


fp=open("\x0a","wb")  #wb表示只写一个二进制文件
fp.write("\x00"*4)
fp.close()

sd = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0);
time.sleep(2)#因为socket连接需要一点时间,如果没有等待很可能连接错误,没有这句话的话就得多运行一遍就好了
sd.connect(("127.0.0.1",8888))
sd.send("\xde\xad\xbe\xef")
sd.close()
  1. 将flag进行软链接到tmp目录下:
    ln -s /home/input2/flag flag
  2. 执行python文件
    过程如下:
    需要先在tmp目录下自行创建一个目录并在该目录下入python文件
    在这里插入图片描述在这里插入图片描述

这里不知道为什么添加注释会报错,将全部注释删除就可以了。

函数讲解
ln -s指令

这个python文件需要放在/tmp文件下,由于flag这里写的是相对地址,因此需要将其进行软链接到tmp目录下。
ln -s /home/input2/flag flag

ln命令 用来为文件创建链接,链接类型分为硬链接和符号链接两种,默认的链接类型是硬链接。如果要创建符号链接必须使用"-s"选项
硬链接的意思是一个档案可以有多个名称,而软链接的方式则是产生一个特殊的档案,该档案的内容是指向另一个档案的位置。硬链接是存在同一个文件系统中,而软链接却可以跨越不同的文件系统
格式:ln [参数][源文件或目录][目标文件或目录]
例如这里用到的指令:ln -s /home/input2/flag flag
更详细的信息可以点击这个链接
其他操作:

查看建立的链接 
ls -l
删除软链接
rm -rf flag
subprocess模块

该模块的popen函数用于查看用户的输入,其基本格式如下:
subprocess.Popen(‘命令’, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
其中shell=true可省略,stdout=subprocess.PIPE表示当命令存在的时候,把结果写入到stdout管道
stderr=sbuprocess.PIPE 表示当命令不存在的时候,把结果吸入到stderr管道
env表示给环境变量赋值,对应与getenv,获取环境变量值

ord函数

该函数是python中的一个将字符(一个字符)转换为int类型数据的函数

os.pipe()

用于创建管道并将信息从一个进程传递给另一个进程,它有一对文件描述符,r和w,一个用于读取数据,一个用于写入数据的,因此在使用时也是成对使用:

stdinr, stdinw = os.pipe()
#写入
os.write(stdinw, "\x00\x0a\x00\xff")
#而要使用写入的值则使用stdinr
TypeError: a bytes-like object is required, not ‘str’

然后在本地运行的时候还报了这个错,而在ssh的链接上则能正常运行。
在这里插入图片描述

主要是pwnable的终端用的是python2,而本地我用的python3,而python3对数据类型进行了更细的划分,在这里把数据当成了str类型,而实际上这里传输的是二进制的数据,因此在字符串前加一个b就可以了。

os.write(stdinw,b"\x00\x0a\x00\xff")

第八题leg

参考链接:

知识点记录
  1. pc寄存器用于存储当前欲执行指令的地址,也就是当前正在执行的指令的下一条指令
  2. bx跳转
    这个可以参看此链接

B、BL、BX、BLX 和 BXJ:
分别对应跳转、带链接跳转(带返回的跳转)、跳转并切换指令集、带链接跳转并切换指令集(带返回的跳转并切换指令集)、跳转并转换到 Jazelle 状态

此处的bx表示跳转并切换指令集,根据地址的最低位确定是否状态切换。如果末尾是1则切换到thumb状态,否则保留在asm状态,而需要注意的是在thumb中pc到下一条地址只需要+4,在asm中则是+8
3. lr寄存器
该寄存器有两个用途,一是用来保存子程序返回地址;二是当异常发生时,LR中保存的值等于异常发生时PC的值减4(或者减2)。
同时,当通过BL或BLX指令调用子程序时,硬件自动将子程序返回地址保存在R14寄存器中。在子程序返回时,把LR的值复制到程序计数器PC即可实现子程序返回

解题过程

打开leg.asm可以看到key1、key2、key3都是获取的r0来进行的计算,因此只需要查看对应函数的r0是怎么得到的即可
在这里插入图片描述

  1. 首先是key1,可以看到它的结果是pc,而pc的值应该是当前执行指令的下一条指令,在ARM汇编指令中,寄存器pc的值为当前指令地址加8个字节,也就是key1=0x00008cdc+8
    在这里插入图片描述

  2. 接下来看key2
    在这里插入图片描述
    红色方框圈出了计算过程,r6=pc+1=0x00008cfc+1,然后对r6执行bx切换,由于r6的二进制为:
    在这里插入图片描述

末位为1会切换到thumb状态,在thumb状态下寄存器的值为当前指令加4,因此r3=0x8d04+4,执行adds后r3再次+4,因此r3=0x8d04+4+4=0x8d0c
在这里插入图片描述
3. 接下来是key3
在这里插入图片描述前面已经提到lr指令存放的是子程序的返回地址,也就是当前指令执行完成后子程序回去继续执行的地方,因此去main中找,也就是0x8d80=key3
在这里插入图片描述

  1. 总结
    通过以上过程我已经知道了key1、2、3,因此直接就可以计算出结果了
    key=key1+key2+key3=0x00008cdc+8+0x8d0c+0x8d80=0x1A772=108400
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值