攻防世界zorropub题解与subprocess模块

news2024/12/23 8:36:08

目录

题目分析:

subprocess模块:

subprocess.Popen()函数:

subprocess.run()函数:

题目脚本:


在攻防世界做到一个题目感觉还挺有意思,记录一下

这个放链接也只是攻防世界的页面,所以直接说题目地址是在攻防世界->Reverse模块->难度3->zorropub.

参考文章:zorropub 攻防世界_北风~的博客-CSDN博客

                    攻防世界 zorropub_路途之后是路途的博客-CSDN博客

题目分析:

下面进入正题:)

在IDA中打开附件,找到主函数

int sub_4009BD()
{
  __int64 v0; // rax
  int input_number; // [rsp+1Ch] [rbp-104h] BYREF
  int input; // [rsp+20h] [rbp-100h] BYREF
  int i; // [rsp+24h] [rbp-FCh]
  unsigned int seed; // [rsp+28h] [rbp-F8h]
  unsigned int v6; // [rsp+2Ch] [rbp-F4h]
  char v7[96]; // [rsp+30h] [rbp-F0h] BYREF
  char v8[16]; // [rsp+90h] [rbp-90h] BYREF
  char v9[32]; // [rsp+A0h] [rbp-80h] BYREF
  char s[32]; // [rsp+C0h] [rbp-60h] BYREF
  char s1[40]; // [rsp+E0h] [rbp-40h] BYREF
  unsigned __int64 v12; // [rsp+108h] [rbp-18h]

  v12 = __readfsqword(0x28u);
  seed = 0;
  puts("Welcome to Pub Zorro!!");
  printf("Straight to the point. How many drinks you want?");
  __isoc99_scanf("%d", &input_number);
  if ( input_number <= 0 )
  {
    printf("You are too drunk!! Get Out!!");
    exit(-1);
  }
  printf("OK. I need details of all the drinks. Give me %d drink ids:", input_number);// 输入数字
  for ( i = 0; i < input_number; ++i )
  {
    __isoc99_scanf("%d", &input);
    if ( input <= 16 || input > 0xFFFF )
    {
      puts("Invalid Drink Id.");
      printf("Get Out!!");
      exit(-1);
    }
    seed ^= input;                              // 根据输入的数字大小输入对应的drink_id,并且与seed异或
  }
  i = seed;
  v6 = 0;
  while ( i )
  {
    ++v6;
    i &= i - 1;                                 // 判断一个数的二进制形式中含有多少个1
  }
  if ( v6 != 10 )
  {
    puts("Looks like its a dangerous combination of drinks right there.");
    puts("Get Out, you will get yourself killed");
    exit(-1);
  }
  srand(seed);
  MD5_Init(v7);
  for ( i = 0; i <= 29; ++i )
  {
    v6 = rand() % 1000;                         // 取随机数
    sprintf(s, "%d", v6);
    v0 = strlen(s);
    MD5_Update(v7, s, v0);                      // MD5加密
    v9[i] = v6 ^ LOBYTE(dword_6020C0[i]);
  }
  v9[i] = 0;
  MD5_Final(v8, v7);
  for ( i = 0; i <= 15; ++i )
    sprintf(&s1[2 * i], "%02x", v8[i]);
  if ( strcmp(s1, "5eba99aff105c9ff6a1a913e343fec67") )// 此处传的是加密结果的前16位
  {
    puts("Try different mix, This mix is too sloppy");
    exit(-1);
  }
  return printf("\nYou choose right mix and here is your reward: The flag is nullcon{%s}\n", v9);
}

函数先是要求输入一个数字a,再输入a个dring_id号,要求大小在16~0xffff之间,并且将这些id号与种子值seed异或,下面的一个while循环时判断seed值的,i&=i-1用来判断一个数的二进制形式中1的个数,也就是要求seed值的二进制形式里要有10个1 .

 接下来就是取30个随机数v6进行MD5加密,传MD5加密结果的前16位来进行判断是否相等,最后的flag就是v6异或数组dword_6020C0的值,这里%02x是以是十六进制形式表示,不足两位的补0

本来是想爆破v6的,还是没搞懂MD5加密,MD5加密,无论输入有多长,输出总是128位也就是32个16进制数,这里传的只是加密结果的前16位。不过也还是可以爆破的,不是从MD5爆破的就是了,看其他大佬的wp才知道可以使用subprocess模块,学到了

subprocess模块:

参考文章:python subprocess模块 - lincappu - 博客园 (cnblogs.com)

                 subprocess  (这个b站的视频也不错)

subprocess模块是Python中自带的一个模块,可以在父进程中创建一个子进程,允许在python中执行外部命令并与其进行交互。嗯我的理解是在一个程序中实现与另一个程序进行输入输出的交流,就类似于我们写一个自动脚本模拟我们与另一个程序进行交流的情况。(个人理解)

subprocess模块包含几个核心函数,这些函数方便启动和控制子进程

subprocess.Popen()函数:

这个函数是subprocess模块最核心,最底层的函数,用于创建一个子进程,可以在该对象上调用方法来与子进程进行交互

class subprocess.Popen(args, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None, 
preexec_fn=None, close_fds=True, shell=False, cwd=None, env=None, universal_newlines=False, 
startupinfo=None, creationflags=0,restore_signals=True, start_new_session=False, pass_fds=(),
*, encoding=None, errors=None)
  • args:shell命令,可以是字符串或者序列类型(如:list,元组)
  • bufsize:缓冲区大小。当创建标准流的管道对象时使用,默认-1。
    0:不使用缓冲区
    1:表示行缓冲,仅当universal_newlines=True时可用,也就是文本模式
    正数:表示缓冲区大小
    负数:表示使用系统默认的缓冲区大小。
  • stdin, stdout, stderr:分别表示程序的标准输入、输出、错误句柄
  • preexec_fn:只在 Unix 平台下有效,用于指定一个可执行对象(callable object),它将在子进程运行之前被调用
  • shell:如果该参数为 True,将通过操作系统的 shell 执行指定的命令。
  • cwd:用于设置子进程的当前目录。
  • env:用于指定子进程的环境变量。如果 env = None,子进程的环境变量将从父进程中继承。

创建一个子进程,然后执行一个简单的命令:

subprocess.run()函数:

.run函数是python3.5之后出现的一个函数,其底层接口还是Popen,不过会更方便,用于运行一个外部命令,等待它完成并返回结果。

subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, capture_output=False, shell=False, cwd=None, timeout=None, check=False, encoding=None, errors=None, text=None, env=None, universal_newlines=None)

  • args:表示要执行的命令。必须是一个字符串,字符串参数列表。
  • stdin、stdout 和 stderr:子进程的标准输入、输出和错误。其值可以是 subprocess.PIPE、subprocess.DEVNULL、一个已经存在的文件描述符、已经打开的文件对象或者 None。subprocess.PIPE 表示为子进程创建新的管道。subprocess.DEVNULL 表示使用 os.devnull。默认使用的是 None,表示什么都不做。另外,stderr 可以合并到 stdout 里一起输出。
  • timeout:设置命令超时时间。如果命令执行时间超时,子进程将被杀死,并弹出 TimeoutExpired 异常。
  • check:如果该参数设置为 True,并且进程退出状态码不是 0,则弹 出 CalledProcessError 异常。
  • encoding: 如果指定了该参数,则 stdin、stdout 和 stderr 可以接收字符串数据,并以该编码方式编码。否则只接收 bytes 类型的数据。
  • shell:如果该参数为 True,将通过操作系统的 shell 执行指定的命令。

 一般的话使用stdin,stdout比较多

补充:

Popen.communicate(): 用于与子进程进行输入输出交互,向子进程发送数据并获取输出结果。

  1. Popen.stdin, Popen.stdout, Popen.stderr: 分别代表子进程的标准输入、标准输出和标准错误输出。

  2. Popen.wait(): 等待子进程结束,并返回其返回码。

  3. 使用时要导入subpeocess ,比如import subprocess这样

import subprocess  #
import shlex  # 帮助分隔命令

process = subprocess.run(shlex.split("python 解密脚本.py"))  # subprocess.run接口
print(process)
# returncode=0表示调用成功,不为0表示调用失败


# subprocess.Popen不会阻断整个程序的运行
process = subprocess.Popen(['python', '解密脚本.py'], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                           stdin=subprocess.PIPE)
# shell表示终端,表示前面的Tree命令要在终端出运行,
# stdout=subprocess.PIPE,其中subprocess.PIPE表示创建一个管道,令stdout=subprocess.PIPE表示命令正常执行的结果丢到stdout这个管道里
# stderr表示命令执行出错的结果丢到这里,注意subprocess.PIPE每次都会创建一个新的管道,会得到一个对象obj接住这个对象
# stdin=subprocess.PIPE表示输入
res = process.stdout.read()  #读取管道信息
print(res.decode('utf-8'))  # 打印出正确执行的结果
process.stdin.write('yes\n'.encode())  # 向Py脚本输入数据使用此。encode表示转为byte类型,模拟与终端的交互
process.stdin.flush()  # 写入
print(process.stdout.read())

下面那这题作为例子具体介绍一下吧

题目脚本:

我们现在需要知道的就是随机数的值,因为没法利用MD5爆破所以只能利用程序自身了,我们知道只要得到符合要求的seed值,就可以进入下面随机数生成的部分,而固定的seed+固定的随机数算法=生成固定的随机数,所以我们只需要看哪一个符合要求的随机数种子得到的随机数是符合最后的加密结果就可以(感觉说的有点绕....就是找到所有符合要求的seed(编写脚本爆破找)->一个一个输入到程序中测试(这一块就可以使用subprocess来搞,手动输入当然是很麻烦)->看哪个seed是可以得到最后结果的)

注意:因为drink_id是在16~0xffff范围,而初始值位0的seed值和他们异或之后的最终结果也是在16~0xffff范围,这样的话,就方便爆破了。

#!/usr/bin/python
# -*- coding: utf-8 -*-
from subprocess import *

# 这里是找出符合条件的数                           //这部分是先找到符合要求的数,即最后的seed,因为我们可以知道input在16到0xffff范围内,那么seed=0循环异或
# 原函数对种子的加密                               //的结果seed也是在这个范围内,那么当循环的次数最少的时候是不是就是找最后seed最简单的时候?,而且也是直接通过进程
a = []
for i in range(16, 65535):
    v9 = 0
    s = i
    while i:
        v9 += 1
        i &= i - 1
    if v9 == 10:
        a.append(s)                              //找出所有符合条件的值,可能不止一个,添加到a列表中
# 循环输入符合条件的数,爆破flag
for i in a:                                        //在符合第一个判断条件a列表中来和程序进行交互,看哪一个数的的输出结果包含flag,就打印这个数
    proc = Popen(['./87356aae634e4e0a9a081f30fc81fe16'], stdin=PIPE, stdout=PIPE)
    #PIPE表示新建输入输出管道,便于下面对管道的读取,若为none会直接在运行窗口输出,无法对其进行操作
    out = proc.communicate(('1\n%s\n' % i).encode('utf-8'))[0]
    #1\n%s\n表示喝一瓶饮料,id号为i,将i转为字符串加入其中,与'1\n%d\n' % i一样
    # 这里communicate与子进程进行输入输出交互,返回的是一个元组,但是元组只有一个元素,所以要加上偏移0,1为标准错误
    if "nullcon".encode('utf-8') in out:
        print(out)
        print(i)

这个脚本需要在linux中运行,但是在因为版本问题,在ubuntu里运行的时候会报错no such file or dictionary,后来问其他大佬,可能是libcrypto版本要求为1.0.0,所以我是运行不了....

最后的输出结果是

nullcon{nu11c0n_s4yz_x0r1n6_1s_4m4z1ng}

当然也可以直接爆破seed的值,然后手动运行程序输入input_number为1,再手动输入seed值拿到结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/828709.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

docker数据持久化

在Docker中若要想实现容器数据的持久化&#xff08;所谓的数据持久化即数据不随着Container的结束而销毁&#xff09;&#xff0c;需要将数据从宿主机挂载到容器中。目前Docker提供了三种不同的方式将数据从宿主机挂载到容器中。 &#xff08;1&#xff09;Volumes&#xff1a;…

【C#学习笔记】值类型(1)

虽然拥有编程基础的人可以很快地上手C#&#xff0c;但是依然需要学习C#的特性和基础。本系列是本人学习C#的笔记&#xff0c;完全按照微软官方文档编写&#xff0c;但是不适合没有编程基础的人。 文章目录 .NET 体系结构Hello&#xff0c;World类型和变量&#xff08;重要&…

分库分表之基于Shardingjdbc+docker+mysql主从架构实现读写分离 (三)

本篇主要说明&#xff1a; 1. 因为这个mysql版本是8.0&#xff0c;所以当其中一台mysql节点挂掉之后&#xff0c;主从同步&#xff0c;甚至双向数据同步都失效了&#xff0c;所以本篇主要记录下当其中的节点挂掉之后如何再次生效。另外推荐大家使用mysql5.7的版本&#xff0c;这…

3-ASCII-座位渲染-二维码

一 ASCII码 1 概念 ascii码是一种计算机信息交换标准,在这个表里面制定了 128个数字跟128个字符的对应关系 我们只关注字母跟数字的对应关系 2 ASCII码转字符 let str String.fromCharCode(数字)二 js对象跟查询字符串互转 a js对象转查询字符串 //创建一个对象 let obj …

新SDK平台下载开源全志D1-H/D1s的SDK

获取SDK SDK 使用 Repo 工具管理&#xff0c;拉取 SDK 需要配置安装 Repo 工具。 Repo is a tool built on top of Git. Repo helps manage many Git repositories, does the uploads to revision control systems, and automates parts of the development workflow. Repo is…

【Python】模块学习之matplotlib柱状图、饼状图、动态图及解决中文显示问题

目录 前言 安装 pip安装 安装包安装 柱状图 主要方法 参数说明 示例代码 效果图 解决中文显示问题 修改后的图片 饼状图 主要方法 示例代码 效果图 动态图 主要方法 动态图官方使用介绍 示例代码 颜色设置 内建颜色 字体设置 资料获取方法 前言 众所周…

WPF上位机6——文件操作、多线程、线程锁、Task异步编程

文件操作 文件夹操作 创建文件夹 磁盘信息 文件的读写 文件流 Thread多线程 带参数创建线程 Task多线程 创建方式1 第一种 第二种 第三种&#xff1a;线程池的方式 前台与后台线程 线程锁 Task异步编程 task任务取消 task返回值 async await异步 并行库Parallel

CEC2014:CEC2014测试函数及多种智能优化算法求解CEC2014对比

目录 一、CEC2014测试函数 二、多种智能优化算法求解CEC2014 2.1 本文参与求解CEC2014的智能优化算法 2.2 部分测试函数运行结果与收敛曲线 三、曲线标记代码(获得代码后可自行更改&#xff09; 一、CEC2014测试函数 CEC2014测试集共有30个单目标测试函数&#xff0…

linux下docker安装、镜像下载、镜像基础操作、容器基础操作

目录 一、环境准备 1、开启虚拟化 2、关闭防火墙 3、yum仓库获取阿里源&#xff08;清华、京东都可以&#xff09; 4、确保能ping到外网 二、安装docker 1、yum安装docker 2、启动docker并设置开机自启 3、安装docker-ce阿里镜像加速器 三、docker基本操作 1、查看版…

如何在项目需求与技术方案未确定的情况下掌控上线时间?

需求不明确与技术方案未确定的挑战 在任何项目管理过程中&#xff0c;需求和技术方案是两个核心环节。理想情况下&#xff0c;我们希望在项目开始阶段就有清晰明确的需求和经过深思熟虑的技术方案。然而&#xff0c;现实中的项目管理往往并不如此理想。 项目需求的重要性 需求…

2023年全新版Java学习路线,精心整理【文中送书福利 】

小伙伴们大家好&#xff0c;这里是动力节点&#xff0c;我们从2009年开始一直在从事Java培训 到今年已经整14年了&#xff0c;虽然现在不缺培训机构&#xff0c;更不缺Java培训&#xff0c;但是像我们这么多年专注这一件事的应该也不多。我们只希望在“专业”两个字上面不断精…

Vue3 基础知识点汇总 自学笔记,记录难点 和 新知识点

1.vue3 基础 1.1vue3基础及创建 npm init vue@latest1.2.熟悉项目目录及关键文字 1.3 组合式API-setup 1.4.组合式 API reactive 和ref 函数 (都是为了生成响应式数据) 1.5.组合式API-computed 计算属性函数 1.6.watch 函数 1.7.组合式API-生命周期函数 1.8.组合式 API-父子…

Spring之事务实现方式及原理

目录 Spring事务简介 Spring支持事务管理的两种方式 编程式事务控制 声明式事务管理 Spring事务角色 未开启事务之前 开启Spring的事务管理后 事务配置 事务传播行为 事务传播行为的可选值 Spring事务简介 事务作用&#xff1a;在数据层保障一系列的数据库操作同成功…

Python之pyinstaller打包exe填坑总结

一、起因 编写了一个提取图片中文字的python脚本&#xff0c;想传给同事使用&#xff0c;但是同事电脑上没有任何python环境&#xff0c;更没有安装python库&#xff0c;因此想到通过pyinstaller打包成exe程序传给同事使用&#xff0c;于是开始了不断地挖坑填坑之旅 import p…

Kafka-消费者组消费流程

消费者向kafka集群发送消费请求&#xff0c;消费者客户端默认每次从kafka集群拉取50M数据&#xff0c;放到缓冲队列中&#xff0c;消费者从缓冲队列中每次拉取500条数据进行消费。

Dockerfile构建SSHD镜像

Dockerfile构建SSHD镜像 基于Dockerfile制作镜像时首先需要建立工作目录&#xff0c;作为生成镜像的工作目录&#xff0c;然后分别创建并编写 Dockerfile文件、需要运行的脚本文件以及要复制到容器中的文件。 1、环境配置&#xff1a; [rootdocker ~]# iptables -F [rootdoc…

用python+PyQt5来编写一个定时关机窗口

一、界面展示 二、源码 import sys from PyQt5.QtWidgets import QDesktopWidget,QApplication, QWidget, QLabel, QVBoxLayout, QPushButton, QSpinBox import osclass AutoShutdownApp(QWidget):def __init__(self):super().__init__()self.setWindowTitle("自动关机应…

Aop监控所有Controller,包括void类型的response中的出参(工具类)

一、主要坐标 <!--aop--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><dependency><groupId>com.google.guava</groupId><artifa…

saas堡垒机定义以及优势简单说明

工作中我们经常可以听到saas这个词语&#xff0c;但对于saas堡垒机相信还有很多人不了解。今天我们就来一起简单聊聊什么是saas堡垒机&#xff0c;saas堡垒机有哪些优势。 saas堡垒机定义 saas堡垒机顾名思义为一款SaaS化堡垒机产品&#xff0c;即一款SaaS运维审计安全系统。…

学习记录——EGE-UNet、R2AU-Net、PHNet、CFNet

EGE-UNet: an Efficient Group Enhanced UNet for skin lesion segmentation 上海交大 2023 MICCAI 基于 U-Net 进行魔改&#xff0c;用于解决医学图像&#xff08;尤其是皮肤病变&#xff09;分割中面临的问题。由于它是针对移动健康应用开发的&#xff0c;解决了当前许多模型…