VSCode IDAPython 开发环境配置

VSCode IDAPython 开发环境配置

开发工具 版本
OS Windows 10
IDA Version IDA Pro 7.5
IDACode(VSCode插件) 0.3.0

0x00 安装IDACode插件

仓库地址 https://github.com/ioncodes/idacode

VSCode中的安装

直接在vscode的插件商店中搜索idacode安装即可

IDA中的安装

  1. 将代码仓库中的/ida目录下所有文件复制到本地IDA的plugins目录下,例如我的是C:\Program Files\IDA 7.5\plugins
  2. 修改上述文件夹中的idacode_utils/settings.py, 端口如无特殊需求保持默认即可, PYTHON设置为本地IDA所使用的python解释器, 例如我使用的是conda的默认解释器: PYTHON = "C:\\ProgramData\\Miniconda3\\python.exe"
  3. 给本地IDA所使用的python解释器安装依赖:python -m pip install --user debugpy tornado
  4. 此时重启IDA, 在插件目录中应该可以看到IDACode这一项, 单击可以看到output栏中有[IDACode] Listening on 127.0.0.1:7065的输出, 说明安装成功

0x01 配置VSCode开发环境

自动补全配置

在vscode的settings(json)中把本地IDA Python库的位置添加进去, 例如我的是 C:\Program Files\IDA 7.5\python\3, 则settings中添加的项为:

"python.autoComplete.extraPaths": [
   "C:\\Program Files\\IDA 7.5\\python\\3"
],
"python.analysis.extraPaths": [
   "C:\\Program Files\\IDA 7.5\\python\\3"
],

此时把ida相关的包import进来就可以用自动补全了:

image.png

连接VSCode与IDA

继续阅读“VSCode IDAPython 开发环境配置”

L3HCTF 2021 Reverse 两道题解 (IDAAAAAA double-joy)

这波reverse全军覆没了属于是,最后1/7。。然后队友依然打到了rank3 orz orz

自己全场只看了两个题,最后0输出,麻了。

IDAAAAAA

这题tmd是个misc题吧

tag: 细节+脑洞

错误的分析方法:dump出来elf然后gdb调试

只给了idb,没有elf,直接打开发现是一个将输入解析为按照+号和-号分隔开的三个数字,比如输入-123+5+6,就会得到-123,5,6三个数字。然后这三个数字直接静态看的话必须满足5个约束条件:

image.png

但是直接在2^32的域上求解这5个方程是求不出解的,然后大家就都懵逼了,甚至开始尝试从中选三个出来解。但是这样即使把所有的情况都解出来也是错误的

正确的分析方法:看给的idb

这个idb其实一打开可以发现有一个断点,我当时脑子里大概有一秒钟疑惑了下为啥有个断点,然后就没管他。。然后就错过了

后面我直接用IDA连gdbserver调试的时候,会发现每次执行完scanf都会直接运行结束,当时以为是IDA抽风了。。没想到是故意的,但凡多想一下这个flag也到手了

然后进入正题,这个断点右键编辑,会发现里面的condition是有idapython脚本的(脚本很长,打开这个断点的时候IDA会卡一会儿):

image.png

撸出来之后:

global jIS40A
jIS40A = [...] # 一个长度1000的list,每个item是一堆bytes
N4QKUt = 0
EpUdLx = 4728923
idaapi.add_bpt(EpUdLx)
uwGgnM = idaapi.bpt_t()
idaapi.get_bpt(EpUdLx, uwGgnM)
uwGgnM.elang = "Python"
uwGgnM.condition = "N4QKUt = {}\n".format(N4QKUt) + 'VLzxDy = idaapi.get_byte(5127584 + N4QKUt)\nVLzxDy -= ord(\'a\')\nif VLzxDy == 0:\n    bYsMTa = 287\n    LjzrdT = b\'lqAT7pNI3BX\'\nelif VLzxDy == 1:\n    bYsMTa = 96\n    LjzrdT = b\'z3Uhis74aPq\'\nelif VLzxDy == 2:\n    bYsMTa = 8\n    LjzrdT = b\'9tjseMGBHR5\'\nelif VLzxDy == 3:\n    bYsMTa = 777\n    LjzrdT = b\'FhnvgMQjexH\'\nelif VLzxDy == 4:\n    bYsMTa = 496\n    LjzrdT = b\'SKnZ51f9WsE\'\nelif VLzxDy == 5:\n    bYsMTa = 822\n    LjzrdT = b\'gDJy104BSHW\'\nelif VLzxDy == 6:\n    bYsMTa = 914\n    LjzrdT = b\'PbRV4rSM7fd\'\nelif VLzxDy == 7:\n    bYsMTa = 550\n    LjzrdT = b\'WHPnoMTsbx3\'\nelif VLzxDy == 8:\n    bYsMTa = 273\n    LjzrdT = b\'mLx5hvlqufG\'\nelif VLzxDy == 9:\n    bYsMTa = 259\n    LjzrdT = b\'QvKgNmUFTnW\'\nelif VLzxDy == 10:\n    bYsMTa = 334\n    LjzrdT = b\'TCrHaitRfY1\'\nelif VLzxDy == 11:\n    bYsMTa = 966\n    LjzrdT = b\'m26IAvjq1zC\'\nelif VLzxDy == 12:\n    bYsMTa = 331\n    LjzrdT = b\'dQb2ufTZwLX\'\nelif VLzxDy == 13:\n    bYsMTa = 680\n    LjzrdT = b\'Y6Sr7znOeHL\'\nelif VLzxDy == 14:\n    bYsMTa = 374\n    LjzrdT = b\'hLFj1wl5A0U\'\nelif VLzxDy == 15:\n    bYsMTa = 717\n    LjzrdT = b\'H6W03R7TLFe\'\nelif VLzxDy == 16:\n    bYsMTa = 965\n    LjzrdT = b\'fphoJwDKsTv\'\nelif VLzxDy == 17:\n    bYsMTa = 952\n    LjzrdT = b\'CMF1Vk7NH4O\'\nelif VLzxDy == 18:\n    bYsMTa = 222\n    LjzrdT = b\'43PSbAlgLqj\'\nelse:\n    bYsMTa = -1\nif bYsMTa < 0:\n    cpu.rsp -= 8\n    cpu.rdi = 4927649\n    cpu.rax = 0\n    idaapi.patch_qword(cpu.rsp, 4202616)\n    idaapi.del_bpt(cpu.rip)\n    cpu.rip = 4263680\nelse:\n    zaqhdD = 0x486195\n    bYsMTa = jIS40A[bYsMTa]\n\n    idaapi.patch_bytes(5117568, bYsMTa)\n    idaapi.patch_bytes(5117488, LjzrdT)\n\n    cpu.rsp -= 8\n    idaapi.patch_qword(cpu.rsp, zaqhdD)\n    cpu.rdi = 5117568\n    cpu.rsi = len(bYsMTa)\n    cpu.rdx = 5117488\n    cpu.rcx = 11\n    cpu.r8 = 5117568\n    cpu.rax = 5117568\n\n    idaapi.add_bpt(zaqhdD)\n    jQfwUA = idaapi.bpt_t()\n    idaapi.get_bpt(zaqhdD, jQfwUA)\n    jQfwUA.elang = "Python"\n    jQfwUA.condition = "N4QKUt = {}\\nSdjOr3 = {}\\n".format(N4QKUt, len(bYsMTa)) + \'bYsMTa = idaapi.get_bytes(cpu.rax, SdjOr3).decode()\\nzaqhdD = 4767838\\nidaapi.add_bpt(zaqhdD)\\njQfwUA = idaapi.bpt_t()\\nidaapi.get_bpt(zaqhdD, jQfwUA)\\njQfwUA.elang = "Python"\\njQfwUA.condition = "N4QKUt = {}\\\\n".format(N4QKUt+1) + bYsMTa\\nidaapi.del_bpt(zaqhdD)\\nidaapi.add_bpt(jQfwUA)\\nidaapi.del_bpt(cpu.rip)\\ncpu.rsp -= 8\\nidaapi.patch_qword(cpu.rsp, zaqhdD)\\ncpu.rip = 4447160\\n\'\n    idaapi.del_bpt(zaqhdD)\n    idaapi.add_bpt(jQfwUA)\n    idaapi.del_bpt(cpu.rip)\n    cpu.rip = 4201909\n'
idaapi.del_bpt(EpUdLx)
idaapi.add_bpt(uwGgnM)
cpu.rsp -= 8
idaapi.patch_qword(cpu.rsp, EpUdLx)
cpu.rip = 4202096

不难发现是在这个脚本里面设置了新的断点,而且在新的断点里面加入了新的condition脚本,然后移动eip到一个能执行到断点的位置,我们condition里面的字节解析出来是:
继续阅读“L3HCTF 2021 Reverse 两道题解 (IDAAAAAA double-joy)”

MIPS PWN 入门

MIPS是一种采取精简指令集(RISC)的指令集架构,突出特点是高性能,广泛被使用在许多电子产品、网络设备、个人娱乐设备与商业设备上,在路由器领域也被广泛应用。虽然今年MIPS所属公司已经宣布放弃对该架构继续进行研发设计,但是其作为x86、arm之后的第三大CPU架构阵营,现在市面上仍有大量的MIPS架构的产品,尤其是路由器芯片。此外,MIPS在学术界也非常受到追捧,很多超算竞赛冠军的设计方案都是MIPS的。就目前来看,MIPS的安全研究还是相对较为有意义的。

MIPS架构基础知识

常用汇编与流水线操作 在MIPS PWN中所常用到的汇编指令如下表所示:

image.png

MIPS架构为精简指令集, 常见的MIPS芯片流水线操作为五级, 如下图

wiki-Fivestagespipeline.png

其中IF =指令提取,ID =指令解码,EX =执行,MEM =存储器访问,WB =寄存器写回. 垂直轴是连续的指令: 横轴是时间. 在图示的情况中,最早的指令处于WB阶段,而最新的指令正在进行指令提取. 对于跳转/分支指令, 当其到达执行阶段且新的程序计数器已经产生时, 紧随其后的下一条指令实际上已经开始执行了. MIPS 规定分支之后的指令总是在分支目标指令之前执行,紧随分支指令之后的位置称为 分支延迟槽. 在没有任何可用操作时,延迟槽将填充空指令(nop)占位. 例如下面这段MIPS汇编代码中,
“`move $a0, $s1“`会在“`jalr“`跳转前执行

.text:0007F944                 move    $t9, $s0
.text:0007F948                 jalr    $t9              
.text:0007F94C                 move    $a0, $s1

这个特性在我们查找gadgets和构造payload的时候要多注意, 这也是MIPS上的PWN相比x86架构来说较为特殊的点之一.

寄存器与调用约定 常用的MIPS寄存器作用如下:

  • “`\$a0“` – “`\$a3“`:函数调用时的参数传递,若参数超过 4 个,则多余的使用堆栈传递
  • “`\$t0“`-“`\$t7“`:临时寄存器
  • “`\$s0“` – “`\$s7“`:保存寄存器,使用时需将用到的寄存器保存到堆栈
  • “`\$gp“`:全局指针,用于取数据(32K访问内);“`\$sp“`:栈指针,指向栈顶
  • “`\$fp“`:栈帧指针;“`\$ra“`:存储返回地址

MIPS的调用约定为被调用者实现堆栈平衡, 参数 1 ~ 4 分别保存在
“`\$a0“` ~ “`\$a3“` 寄存器中,剩下的参数从右往左依次入栈. MIPS的栈布局如下图所示, 某寄存器在堆栈中的位置不是确定的, 例如“`\$ra“`在某函数栈中的偏移是“`\$sp“`+N, 而在另一函数栈中的偏移是“`\$sp“`+M.

image.png

当CPU执行跳转到被调用函数后, 被调用函数将会开辟新的栈帧, 根据本函数内是否还有其他函数调用决定是否将
“`\$ra“` 入栈, 再将“`\$sp“` 入栈. 对于“`\$ra“`, 当本函数为叶子函数(函数内无其他函数调用), 则“`\$ra“`不入栈, 否则将“`\$ra“`入栈. 对于栈溢出攻击而言, 当函数为非叶子函数时, 可以直接通过覆盖栈上的“`\$ra“`来劫持控制流.

缓存非一致性
继续阅读“MIPS PWN 入门”

BUUOJ Web #1 [HCTF 2018]WarmUp [强网杯 2019] 随便注 [SUCTF 2019]EasySQL [RoarCTF 2019]Easy Calc

0x01 [HCTF 2018] WarmUp [PHP][代码审计]

题目链接

简单题。打开网页后一张滑稽,按F12寻找信息,发现代码注释里有一行
“`“`,在url后加上/source.php刷线页面,得到一段PHP代码。

<?php
    highlight_file(__FILE__);
    class emmm
    {
        public static function checkFile(&$page)
        {
            $whitelist = ["source"=>"source.php","hint"=>"hint.php"];
            if (! isset($page) || !is_string($page)) {
                echo "you can't see it";
                return false;
            }

            if (in_array($page, $whitelist)) {
                return true;
            }

            $_page = mb_substr(
                $page,
                0,
                mb_strpos($page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }

            $_page = urldecode($page);
            $_page = mb_substr(
                $_page,
                0,
                mb_strpos($_page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }
            echo "you can't see it";
            return false;
        }
    }

    if (! empty($_REQUEST['file'])
        && is_string($_REQUEST['file'])
        && emmm::checkFile($_REQUEST['file'])
    ) {
        include $_REQUEST['file'];
        exit;
    } else {
        echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
    }  
?>

看这个判断语句

if (! empty($_REQUEST['file'])
        && is_string($_REQUEST['file'])
        && emmm::checkFile($_REQUEST['file'])
    )

说明是在请求中包含有文件,以及文件是一个string,这两个都好说,看第三个是进入checkFile函数。

看代码逻辑的话,有三种情况会返回true
继续阅读“BUUOJ Web #1 [HCTF 2018]WarmUp [强网杯 2019] 随便注 [SUCTF 2019]EasySQL [RoarCTF 2019]Easy Calc”