zorropub

 seed = 0;
  puts("Welcome to Pub Zorro!!");
  printf("Straight to the point. How many drinks you want?");
  __isoc99_scanf("%d", &drinksNum);             // 0
  if ( drinksNum <= 0 )
  {
    printf("You are too drunk!! Get Out!!");
    exit(-1);
  }
  printf("OK. I need details of all the drinks. Give me %d drink ids:", drinksNum);
  for ( i = 0; i < drinksNum; ++i )             // drinksNum=1023
  {
    __isoc99_scanf("%d", &ids_num);             // ids_num =1023
    if ( ids_num <= 16 || ids_num > 0xFFFF )
    {
      puts("Invalid Drink Id.");
      printf("Get Out!!");
      exit(-1);
    }
    seed ^= ids_num;                            // seed =0
  }
  i = seed;
  randd = 0;
  while ( i )                                   // i=1023
  {
    ++randd;
    i &= i - 1;
  }
  if ( randd != 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((__int64)ctx);
  for ( i = 0; i <= 29; ++i )
  {
    randd = rand() % 1000;
    sprintf(randdd, "%d", randd);
    len = strlen(randdd);
    MD5_Update(ctx, randdd, len);
    v12[i] = randd ^ LOBYTE(dword_6020C0[i]);
  }
  v12[i] = 0;
  MD5_Final(v11, ctx);
  for ( i = 0; i <= 15; ++i )
    sprintf(&s1[2 * i], "%02x", (unsigned __int8)v11[i]);
  if ( strcmp(s1, "5eba99aff105c9ff6a1a913e343fec67") )
  {
    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", v12);
}

程序使用srand(seed)生成伪随机数。我们可以便携python脚本先找到符合条件的seed。然后爆破进程,把seed一个一个尝试。

i &= i - 1	//清除整数二进制表示中最右侧的1

统计二进制中 1 的个数

int count = 0;
int i = 12; // 1100
while (i != 0) {
    i &= i - 1;
    count++; // 最终count=2(12的二进制有2个1)
}

subprocess --- 子进程管理

subprocess 模块允许你生成新的进程,连接它们的输入、输出、错误管道,并且获取它们的返回码。

subprocess.Popen

subprocess模块定义了一个类: Popen

class subprocess.Popen( args, #参数,可以是字符串,列表。
  bufsize=0,      #0表示不缓冲,1表示缓冲
  executable=None,#指定要执行的程序
  stdin=None,     #子进程的标准输入
  stdout=None,    #子进程的标准输出
  stderr=None,    #子进程的标准错误
  preexec_fn=None, 
  close_fds=False, 
  shell=False,    #指定命令在shell中解析
  cwd=None, 
  env=None, 
  universal_newlines=False, 
  startupinfo=None, 
  creationflags=0)
  • 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 执行指定的命令。

communicate函数

communicate函数用于与子进程进行交互。它在子进程中执行一个命令,并返回两个元素的元组:标准输出和标准错误。

下面是communicate函数的基本用法示例:

import subprocess

# 执行命令
result = subprocess.Popen(["ls", "-l"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# 与子进程进行交互
output, error = result.communicate()

print(output.decode())
print(error.decode())

多个输入和输出

import subprocess

# 执行命令
p = subprocess.Popen(["grep", "hello"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)

# 向子进程提供多个输入
input_data = "hello world\ngoodbye world\nhello cat\n"
output = p.communicate(input=input_data.encode('utf-8'))[0]#返回元组,0表示是标准输出,1表示是标准错误

# 从子进程获取多个输出
result = output.decode().strip().split("\n")
print(result)

解题脚本

import subprocess

seed=0
seedd=[]


for ids_num in range(17,0xffff):
    seed ^=ids_num
    i=seed
    randd=0
    if i<1023:
        continue
    while(i):
        randd=randd+1
        i &= i-1
    if randd ==10:
        print("ids_num=",ids_num)
        seedd.append(ids_num)

for i in seedd:
    proc = subprocess.Popen(['./87356aae634e4e0a9a081f30fc81fe16'],stdin=subprocess.PIPE,stdout=subprocess.PIPE)
    inputdata='1\n%s\n'%i
    out=proc.communicate(input=inputdata.encode('utf-8'))[0]
    if 'nullcon'.encode('utf-8') in out:
        print(out)
        print(i)
posted @ 2025-07-28 09:49  MillionMind  阅读(11)  评论(0)    收藏  举报