【pwnable.kr】 codemap

pwnable新的一题。

download: http://pwnable.kr/bin/codemap.exe

ssh [email protected] -p2222 (pw:guest)

这道题虽然是在pwnable下,但是是一道逆向题。。。 //前web狗膜一发二进制大佬

根据提示,需要查看 0x403E65 运行时,寄存器 EAX,EBX 的内容。

先不考虑运行的内容,先看程序。首先这个程序没有加壳,直接可以用ida查看内容.

然后可以看到程序的框架,在main函数中,默默按下F5...

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int seed; // [email protected]
  int (***v4)(void); // [email protected]
  int (***v5)(void); // [email protected]
  int v6; // [email protected]
  int (**v7)(void); // [email protected]
  int (***random_funtion)(void); // [email protected]
  unsigned int v9; // [email protected]
  unsigned int v10; // [email protected]
  char *eax_now_str; // [email protected]
  unsigned int i; // [email protected]
  char *max_eax_str; // [sp+10h] [bp-60h]@0
  unsigned int eax_now; // [sp+14h] [bp-5Ch]@8
  unsigned int count; // [sp+18h] [bp-58h]@1
  unsigned int max_eax; // [sp+1Ch] [bp-54h]@1
  char word_str; // [sp+20h] [bp-50h]@9
  int v19; // [sp+6Ch] [bp-4h]@3

  printf("I will make 1000 heap chunks with random size\n");
  printf("each heap chunk has a random string\n");
  printf("press enter to start the memory allocation\n");
  sub_3440B1();
  max_eax = 0;
  count = 0;
  srand(0);
  while ( 1 )
  {
    seed = 10000 * rand() % 1337;
    v4 = (int (***)(void))operator new(8u);
    v5 = v4;
    v19 = 0;
    if ( v4 )
    {
      *v4 = (int (**)(void))&off_34F2EC;
      v6 = (10000 * seed >> 1) + 123;
      v7 = (int (**)(void))operator new(8u);
      if ( v7 )
      {
        v7[1] = (int (*)(void))v6;
        v5[1] = v7;
        random_funtion = v5;
      }
      else
      {
        v5[1] = 0;
        random_funtion = v5;
      }
    }
    else
    {
      random_funtion = 0;
    }
    v19 = -1;
    v9 = (**random_funtion)();
    v10 = v9 % 0x186A0;
    eax_now = v9 % 0x186A0;
    eax_now_str = (char *)malloc(v9 % 0x186A0);
    if ( v10 >= 0x10 )
    {
      qmemcpy(&word_str, "abcdefghijklmnopqrstubwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890", 0x3Fu);
      i = 0;
      do
        eax_now_str[++i - 1] = *(&word_str + rand() % 62);
      while ( i < 0xF );
      eax_now_str[15] = 0;
      if ( eax_now > max_eax )
      {
        max_eax = eax_now;
        max_eax_str = eax_now_str;
      }
    }
    if ( ++count >= 0x3E8 )                     // 0x3e8 = 1000
      break;
    srand(count);
  }
  printf("the allcated memory size of biggest chunk is %d byte\n", max_eax);
  printf("the string inside that chunk is %s\n", max_eax_str);
  printf("log in to pwnable.kr and anwer some question to get flag.\n");
  sub_3440B1();
  return 0;
}

这是把F5以后的反编译程序,加上自己的理解改成了这个样子。

这个是一个循环申请内存空间,并随机填充16个a~Z0~9字符的程序,循环次数为1000次。

每次循环后,找到申请空间最大的那次,并打印出来。

上面最重要的是random_function变量,它的结果是下图这些sub_*的函数,内容就是根据现在的执行上下文生成一个随机数。

由于上面代码中用的随机函数都是伪随机,或者种子固定,因此,每次运行该程序,申请的大小、字符串的添加都是一样的。

而题目中给的提示,EAX、EBX是执行的结果,其中EAX存储的是申请内存的大小、EBX存储一个char指针,指向填充的字符串。

做了以上分析之后,可以想出解决思路,每次在该位置下断点,获取EAX、EBX的内容,最后做删选即可。

而通过服务器上所给的提示,随后需要提交第二、第三大分配内存块所填充的字符串内容。

由于做了1000次循环,因此人工寻找几乎不可能。

还好ida工具有ida 脚本这样一种工具,可以动态获取指定内容。

可以编写ida脚本来完成查找。我使用了IDA Python这一工具。其实和idc基本相同。

思路就是下断点——获取EAX\EBX的值,最终进行比较,由于没想到好的排序算法,就直接采用最简单粗暴的方法

脚本如下,另外每次程序加载到内存中的位置不同,使用时应修改添加断点的内存地址。

from idaapi import *
from idc import *
import os

count = 0
eax_list = list()
ebx_list = list()

try:
    if debugger:
        print("Removing previous hook ...")
        debugger.unhook()
except:
    pass
AddBpt (0x403e65)
print "[*] set hook OK...\n"
StartDebugger("","","")
for i in range(0,999):
    GetDebuggerEvent(WFNE_SUSP|WFNE_CONT, -1)
    print "[+]",i
    eax = GetRegValue("EAX")
    eax_list.append(eax)
    ebx = GetRegValue("EBX")
    ebx_list.append(ebx)
    if i == 998:
        print ‘[+] eax max : ‘,max(eax_list)
        index = eax_list.index(max(eax_list))
        a = ebx_list[index]
        #message( "[+] ebx max : %x",%(ebx_list[eax_list.index(max(eax_list))]))
        Message("%x"%a)
        print "max",GetString(a)
        del(eax_list[index])
        del(ebx_list[index])
#
        print ‘[+] eax second : ‘,max(eax_list)
        index = eax_list.index(max(eax_list))
        a = ebx_list[index]
        #message( "[+] ebx max : %x",%(ebx_list[eax_list.index(max(eax_list))]))
        Message("%x"%a)
        print "second",GetString(a)
        del(eax_list[index])
        del(ebx_list[index])
#
        print ‘[+] eax third : ‘,max(eax_list)
        index = eax_list.index(max(eax_list))
        a = ebx_list[index]
        #message( "[+] ebx max : %x",%(ebx_list[eax_list.index(max(eax_list))]))
        Message("%x"%a)
        print "third",GetString(a)
        del(eax_list[index])
        del(ebx_list[index])

最终,运行的结果如下:

nc 0 9021输入字符串之后可以获得该题的flag:

时间: 2024-10-14 05:59:49

【pwnable.kr】 codemap的相关文章

【pwnable.kr】bof

pwnable从入门到放弃,第三题. Download : http://pwnable.kr/bin/bofDownload : http://pwnable.kr/bin/bof.c Running at : nc pwnable.kr 9000 很简单的一道栈溢出题目. 依然先读代码: #include <stdio.h> #include <string.h> #include <stdlib.h> void func(int key){ char overfl

【pwnable.kr】leg

pwnable从入门到放弃第八题. Download : http://pwnable.kr/bin/leg.cDownload : http://pwnable.kr/bin/leg.asm ssh [email protected] -p2222 (pw:guest) 先下载这两个文件:leg.c #include <stdio.h> #include <fcntl.h> int key1(){ asm("mov r3, pc\n"); } int key2

【pwnable.kr】 asm

一道写shellcode的题目, #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/mman.h> #include <seccomp.h> #include <sys/prctl.h> #include <fcntl.h> #include <unistd.h> #define LENGTH 128 void sa

【pwnable.kr】 unlink

pwnable.kr 第一阶段的最后一题! 这道题目就是堆溢出的经典利用题目,不过是把堆块的分配与释放操作用C++重新写了一遍,可参考<C和C++安全编码一书>//不是广告 #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct tagOBJ{ struct tagOBJ* fd; struct tagOBJ* bk; char buf[8]; }OBJ; void

【pwnable.kr】 flag

pwnable从入门到放弃 第四题 Download : http://pwnable.kr/bin/flag 下载下来的二进制文件,对着它一脸懵逼,题目中说是逆向题,这我哪会啊... 用ida打开看一下源代码,居然没有main函数. 继续懵逼. 对, 又一次看了别人的题解,居然是加壳的,怪不得图片就是个壳,我哪会砸壳啊??? 还好有工具,轮子大法好,用strings命令发现程序有许多"UPX"字符串,是UPX壳. 在GitHub上找了一个UPX壳砸壳自动化工具: https://gi

【pwnable.kr】blackjack

又一道pwnable nc pwnable.kr 9009 读题找到源代码在:http://cboard.cprogramming.com/c-programming/114023-simple-blackjack-program.html 第一反应是源代码这么长,还不如先玩玩看. 首先,看一下游戏规则发现和21点游戏是一样的,可能国外就叫blackjack吧. 每次,让游戏中下注,然后和电脑比赛,下注的金额不能超过所持有的金额. 这尼玛发牌函数也是随机的,就算你运气再好,算法再牛,想挣100w

【pwnable.kr】 mistake

又一道pwnable,我还没放弃.. ssh [email protected] -p2222 (pw:guest) 源代码如下: #include <stdio.h> #include <fcntl.h> #define PW_LEN 10 #define XORKEY 1 void xor(char* s, int len){ int i; for(i=0; i<len; i++){ s[i] ^= XORKEY; } } int main(int argc, char*

【pwnable.kr】 shellshock

pwnable从入门到放弃,第五题. ssh [email protected] -p2222 (pw:guest) 这题主要涉及了一个关于bash的CVE漏洞. 首先还是下载源代码审计一下,shellshock.c #include <stdio.h> int main(){ setresuid(getegid(), getegid(), getegid()); setresgid(getegid(), getegid(), getegid()); system("/home/sh

【pwnable.kr】 uaf

目测是比较接近pwnable的一道题.考察了uaf(use after free的内容),我觉得说白了就是指针没有初始化的问题. ssh [email protected] -p2222 (pw:guest) 先看一下代码 #include <fcntl.h> #include <iostream> #include <cstring> #include <cstdlib> #include <unistd.h> using namespace