热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

具有重金属风格的调试艺术:如何在IBM大型机上面进行逆向分析

 相关术语zOS:IBM的大型机操作系统;TSO:分时选择程序,用于对zOS系统进行交互式访问;PDS:zOS文件夹;HLASM:高级汇编语言,z/架构上的汇编语言;TSO TEST: 预装在zOS上

 

相关术语



  • zOS:IBM的大型机操作系统;

  • TSO:分时选择程序,用于对zOS系统进行交互式访问;

  • PDS:zOS文件夹;

  • HLASM:高级汇编语言,z/架构上的汇编语言;

  • TSO TEST: 预装在zOS上的终端调试器,它并非真正用于逆向工程;

  • AMBLIST: 用于映射加载模块和程序对象的批处理程序;

  • JCL:作业控制语言,用于提交批处理程序;

  • USS:Unix子系统,类似wsl,只不过运行在zOS上。

 

简介

在zOS系统上进行逆向工程时,会面临诸多挑战,其中最大的挑战是如何迈出第一步。

首先,zOS系统上可用的工具并不适合逆向工程,因为IBM创建它们的初衷,是为了调试应用程序。在本文中,我选择使用的应用程序是TSO TEST,因为它是免费的(前提是您能访问zOS,我是通过zPDT的许可副本来访问它的),并且会默认安装在每台IBM大型机上(甚至是TK4上面,它是20世纪80年代的开源zOS系统的前身)。

在如何使用TSO TEST和HLASM方面,IBM的文档介绍的相当详尽。然而,IBM并没有提供快速入门指南,所以需要花很多时间去翻阅IBM的文档;所以,本文就应运而生了,我们旨在提供一份逆向分析zOS应用程序的快速入门资料。

 

如何在zOS系统上编译和运行C程序

为了便于学习逆向分析技术,我们首先要准备好一个编译好的程序。为此,我们将以下面的示例代码为例,来演示如何编译和运行C程序;当然,这份代码中明显含有溢出漏洞。

#include
#include
void special()
{
printf ("H4CK3D TH3 M41NFR4M3");
}
int main()
{
char buff[15];
int pass = 0;
printf("\n Enter the password : \n");
gets(buff);
if(strcmp(buff, "fsecure"))
{
printf ("\n Wrong Password \n");
}
else
{
printf ("\n Correct Password \n");
pass = 1;
}
if(pass)
{
special();
}
return 0;
}

现在,我们有了C语言的源代码,接下来我们要对其进行编译。为此,这里将使用USS,因为我发现它比提交批处理JCL要更容易一些,但两者的作用是一样的。之后,目标文件被编译成一个MVS PDS数据集。

c89 -o "//'JAKE.TSOTEST.LOADE(OVERFLOW)'" overflow.c

下面是通过批处理文件运行的、用于编译、绑定和运行C程序的作业。

//COMPC JOB (JOBNAME),'XSS',CLASS=A,NOTIFY=&SYSUID
//PROC JCLLIB ORDER=(CBC.SCCNPRC)
//*-------------------------------------------------------------------
//* Compile and bind step
//*-------------------------------------------------------------------
//COMP EXEC EDCCB,
// OUTFILE='JAKE.TSOTEST.LOADE(OVERFLOW),DISP=SHR',
// CPARM='ASM'
//STEPLIB DD DSN=CBC.SCCNCMP,DISP=SHR
// DD DSN=CEE.SCEERUN,DISP=SHR
// DD DSN=CEE.SCEERUN2,DISP=SHR
//COMPILE.SYSIN DD DSN=JAKE.SOURCE.C(OVERFLOW),DISP=SHR
//*-------------------------------------------------------------------
//* Run step
//*-------------------------------------------------------------------
//GO EXEC PGM=OVERFLOW
//STEPLIB DD DSN=JAKE.TSOTEST.LOADE,DISP=SHR

现在,我们就可以通过TSO来调用该程序了。

call 'JAKE.TSOTEST.LOADE(OVERFLOW)'
Enter the password :
testtest
Wrong Password

要对该程序进行静态分析,可以使用AMBLIST;同样,我们也可以利用批处理方式来运行它,不过,使用USS命令会更简单一些。

echo " LISTLOAD OUTPUT=MAP MEMBER=(OVERFLOW)" | amblist "//'JAKE.TSOTEST.LOADE'" > /tmp/overflow_amblist

同样,下面的JCL用于处理同样的事情,只不过它使用了批处理方式。

//AMBLIST JOB (ACCT),MSGCLASS=H,NOTIFY=&SYSUID
//AMBL EXEC PGM=AMBLIST,REGION=64M
//SYSPRINT DD DSN=JAKE.AMBLIST(OVERFLOW),DISP=OLD
//AMBLIB DD DSN=JAKE.TSOTEST.LOADE,DISP=SHR
//SYSIN DD *
LISTLOAD DDN=AMBLIB,OUTPUT=MAP,MEMBER=OVERFLOW
/*

实际上,这些输出内容是非常冗长的,但这里仅摘录了重要信息的片段,例如使用了哪些外部函数,以及函数在编译后的overflow.c二进制文件中的位置;这里显示的是关于SPECIAL和MAIN函数的信息。

-** END OF MAP AND CROSS-REFERENCE LISTING
1 * M O D U L E S U M M A R Y *
0 MEMBER NAME: OVERFLOW MAIN ENTRY POINT: 00000000
0 LIBRARY: SYSLIB AMODE OF MAIN ENTRY POINT: 31
- CONTROL SECTION ENTRY
LMOD LOC NAME LENGTH TYPE RMODE LMOD LOC CSECT LOC NAME
A0 @ST00001 348 SD 31
138 98 SPECIAL
1B8 118 MAIN
338 CEEMAIN 0C SD 31
15A8 gets 0A SD 31
15A8 00 GETS
0 15B8 printf 0A SD 31
15B8 00 PRINTF
0LENGTH OF LOAD MODULE 1D58

现在开始实际调试;为此,可以从TSO运行下面的命令:

test 'JAKE.TSOTEST.LOADE(OVERFLOW)'

现在,我们位于TEST终端;要想离开该终端,可以键入“end”命令。当我们被一条指令卡住的时候,可以按PA1来取消该指令。

 

TSO测试指南

下面是一个TSO测试的例子。

在TEST中,有多种方法来表示地址:


  • 15r:寄存器15中的地址;

  • OVERFLOW.MAIN:使用符号表示地址;

  • +12:相对于基地址的偏移量(以字节为单位;同时,可以使用qualify来改变基地址);以入口点为起始位置;

  • 1FAA12F8:绝对地址。

另外,下面是常用的TEST子命令,我们最好熟悉一下:



  • LIST
    m()
    其中,比较重要的数据类型为i(指令)、b(二进制)、x(十六进制)、c(字符),这里的m表示想显示多少种数据类型。


  • LISTPSW
    显示PSW,以查看条件标志。


  • AT
    , AT
    在一个地址或多个地址上设置断点;对于多个地址,对应位置存放的必须都是指令。

  • `off
    , off .
    删除断点

  • GO
    运行程序,直到出现断点为止。


  • QUALIFY

    改变基地址。


  • WHERE
    输出当前位置以及您所在的函数。

 

逆向分析之旅



寻找密码

以下是HLASM中的寄存器的典型用途:


  • 寄存器1→参数列表指针

  • 寄存器13→指向调用方提供的寄存器保存区的指针

  • 寄存器14→返回地址

  • 寄存器15→子程序的地址

首先,我们需要在MAIN函数处设置一个断点并跳转到该函数。同时,让我们修改一下基地址,具体如下所示:

at OVERFLOW.MAIN
go
qualify OVERFLOW.MAIN

让我们看看接下来要运行哪个指令:

list +0 i
+0 BC 15,36(,R15)

TSO TEST在显示指令时,竟然使用了十进制,但地址通常都是用十六进制表示的。这说明这是一个条件分支指令,掩码1111(总是这个值)用于处理0x24+寄存器15的值。所以,让我们将基地址设为从main函数的起始地址+24字节处,并显示main函数中的所有汇编指令。

qualify +24
list +0 i m(200)
+0 STM R14,R5,12(R13)
+4 L R14,76(,R13)
+8 LA R0,208(,R14)
+C CL R0,788(,R12)
+10 BRC 2,*-32
+14 L R15,640(,R12)
+18 STM R15,R0,72(R14)
+1C MVI 0(R14),16
+20 ST R13,4(,R14)
+24 LR R13,R14
+26 LARL R3,*+210
+2C LARL R5,*+216
+32 MVHI 176(R13),0
+38 L R15,0(,R3)
+3C LA R0,22(,R5)
+40 LA R1,152(,R13)
+44 ST R0,152(,R13)
+48 BASR R14,R15
+4A LA R0,160(,R13)
+4E L R15,4(,R3)
+52 LA R1,152(,R13)
+56 ST R0,152(,R13)
+5A BASR R14,R15
+5C LA R2,160(,R13)
+60 LA R1,48(,R5)
+64 LA R0,0
+68 CLST R2,R1
+6C LA R0,0
+70 ST R2,180(,R13)
+74 ST R1,184(,R13)
+78 ST R0,188(,R13)
+7C BRC 8,*+30
+80 L R2,180(,R13)
+84 L R1,184(,R13)
+88 LLC R0,0(,R2)
+8E LLC R1,0(,R1)
+94 SLR R0,R1
+96 ST R0,188(,R13)
+9A L R0,188(,R13)
+9E LTR R0,R0
+A0 BRC 8,*+26
+A4 L R15,0(,R3)
+A8 LA R0,56(,R5)
+AC LA R1,152(,R13)
+B0 ST R0,152(,R13)
+B4 BASR R14,R15
+B6 BRC 15,*+28
+BA L R15,0(,R3)
+BE LA R0,76(,R5)
+C2 LA R1,152(,R13)
+C6 ST R0,152(,R13)
+CA BASR R14,R15
+CC MVHI 176(R13),1
+D2 L R0,176(,R13)
+D6 LTR R0,R0
+D8 BRC 8,*+10
+DC L R15,8(,R3)
+E0 BASR R14,R15
+E2 LA R15,0
+E6 LR R0,R13
+E8 L R13,4(,R13)
+EC L R14,12(,R13)
+F0 LM R2,R5,28(R13)
+F4 BALR R1,R14
+F6 BCR 0,R7
+F8 SLR R10,R0
+FA LDR FR6,FR0
+FC SLR R10,R0
+FE LDR FR5,FR0
+100 SLR R10,R0
+102 LCR R3,R0
+104 LPD R15,978(R12),964(R15)
+10A STH R14,2291(R3,R12)
+10E STH R13,1265(R4,R15)
+112 CLC 2548(199,R13),1267(R13)
IKJ57245I INVALID INSTRUCTION CODE AT +118

为了更好地理解程序中发生的事情,让我们看看对外部函数的调用。下面的代码的意思是跳转到寄存器15中存放的地址处,并将函数的返回存储在寄存器14中。

+48 BASR R14,R15

所以,让我们在这个地址上设一个断点,并找出寄存器15中的内容。

at +48
go
list 15r
15R 1FA02860

好了,我们知道它跳转到什么位置了,现在设置一个断点,然后运行“where”指令,来看看最后进入哪个函数中。

at 1FA02860.
go
where
1FA02860. LOCATED AT +0 IN OVERFLOW.printf UNDER TCB LOCATED AT 8B9E88.

所以,我们知道这是printf函数,为此,可以在下一个地址处设置一个断点,以便进行相应的验证。

at +4A
go
Enter the password :

让我们对下一个函数做同样的处理,我们的研究发现,会进行如下所示的函数调用:

+5A BASR R14,R15

接下来的C函数称为strcmp,它的情况略有不同。实际上,HLASM有点像CISC,它有一条用于比较字符串的汇编指令“CLST”,如果字符串相同,则设置条件代码。下面的汇编代码显示了要比较的字符串,如果它们相等,就进行条件分支转移。

+68 CLST R2,R1
+6C LA R0,0
+70 ST R2,180(,R13)
+74 ST R1,184(,R13)
+78 ST R0,188(,R13)
+7C BRC 8,*+30

让我们在CLST指令上设置断点,以便看看正在比较的两个字符串。

at +68
list 1r:2r
1R 1FA01508 2R 1FAA02E8
list 1FA01508. c m(30)
1FA01508. f
1FA01509. s
1FA0150A. e
1FA0150B. c
1FA0150C. u
1FA0150D. r
1FA0150E. e
1FA0150F. .
list 1FAA02E8. c m(30)
1FAA02E8. a
1FAA02E9. b
1FAA02EA. c
1FAA02EB. d

从这里我们看到,它将我们输入的字符串“abcd”与“fsecure”字符串进行了比较。

让我们再次调用该程序,并尝试将fsecure作为输入的密码。

call 'JAKE.TSOTEST.LOADE(OVERFLOW)'
Enter the password :
fsecure
Correct Password
H4CK3D TH3 M41NFR4M3


缓冲区溢出

现在,让我们看看如何在没有输入正确的密码的情况下,如何攻破这个大型机。显然,这里将利用缓冲区利用漏洞,不过在此之前,先让我们看看它在HLASM中是如何工作的。

为此,我们可以在main函数的每条指令上设置一个断点。这样的话,输入go指令,就能实现单步跳过(step over)功能。

at +0:+112

注意下面的指令,无论密码是错是对,它都会被运行。MVHI是“MoVe fullword from Halfword Immediate”的意思,并将pass的值设置为0,随后如果程序将该内存加载到寄存器中,运行“LTR”来加载并测试寄存器,将第二个寄存器的值放入第一个寄存器,并检查其内容是否为0。

+32 MVHI 176(R13),0
...
+D2 L R0,176(,R13)
+D6 LTR R0,R0

如果密码正确,就将该变量的值设置为1。

+CC MVHI 176(R13),1

然后,让我们转到D2,来看看寄存器13的值是多少。

at +D2
go
list 13r
13R 1FAA1248

现在,让我们让1FAA1248与176相加,得到1FAA12F8,并查看这个地址所在的二进制到代码。正如我们所看到的,当密码输入正确时,该值被设置为1。

list 1FAA12F8. B m(4)
1FAA12F8. 00000000
1FAA12F9. 00000000
1FAA12FA. 00000000
1FAA12FB. 00000001

从上一节我们知道,我们获取的数据存储在1FAA12E8处。由于每个字符占1个字节,所以要覆盖这个数据,我们需要由1FAA12FB – 1FAA12E8 = 20个字符组成的密码。

call 'JAKE.TSOTEST.LOADE(OVERFLOW)'
Enter the password :
aaaaaaaaaaaaaaaaaaaa
Wrong Password
H4CK3D TH3 M41NFR4M3

注意事项1:在整个过程中,绝对地址可能已经改变了。

注意事项2:zOS编译器似乎没有实现金丝雀、ASLR或NX位等内存保护机制,但虚拟地址的工作方式为zOS提供了很多保护。对于大多数地址间的通信,用户都被要求处于Modeset 0状态,这是一个用户可以拥有的最大特权。面是关于zOS的虚拟内存映射的进一步信息,请参阅http://zseries.marist.edu/pdfs/ztidbitz/29%20zNibbler%20%28zOS%27%20Address%20Space%20%20-%20Virtual%20Storage%20Layout%29.pdf。

注意事项3:zOS系统并没有提供堆栈。按照惯例,zOS系统上的C和其他IBM编译器,会创建相应的DSA(https://www.ibm.com/docs/en/zos/2.2.0?topic=conventions-language-environment-dynamic-storage-area-non-xplink),就像其他系统中的每个函数都有一个堆栈一样。

 

未来的工作

为了实现权限升级,我们将需要滥用管理程序状态。在zOS系统上,这可以通过某些方法来实现,即SVC、APF库和跨内存服务。在接下来的文章中,将介绍如何利用这些方法实现提权。

 

参考资料

POoP(操作原则):


  • Introduction to Assembler Programming SHARE Boston 2013

  • Mainframe [z/OS] reverse engineering and exploit development



推荐阅读
  • 【技术解析】深入探讨堆利用中的UAF漏洞及其影响 ... [详细]
  • 我正在使用 Ruby on Rails 构建个人网站。总体而言,RoR 是一个非常出色的工具,它提供了丰富的功能和灵活性,使得创建自定义页面变得既高效又便捷。通过利用其强大的框架和模块化设计,我可以轻松实现复杂的功能,同时保持代码的整洁和可维护性。此外,Rails 的社区支持也非常强大,为开发过程中遇到的问题提供了丰富的资源和解决方案。 ... [详细]
  • Understanding the Distinction Between decodeURIComponent and Its Encoding Counterpart
    本文探讨了 JavaScript 中 `decodeURIComponent` 和其编码对应函数之间的区别。通过详细分析这两个函数的功能和应用场景,帮助开发者更好地理解和使用它们,避免常见的编码和解码错误。 ... [详细]
  • BZOJ4240 Gym 102082G:贪心算法与树状数组的综合应用
    BZOJ4240 Gym 102082G 题目 "有趣的家庭菜园" 结合了贪心算法和树状数组的应用,旨在解决在有限时间和内存限制下高效处理复杂数据结构的问题。通过巧妙地运用贪心策略和树状数组,该题目能够在 10 秒的时间限制和 256MB 的内存限制内,有效处理大量输入数据,实现高性能的解决方案。提交次数为 756 次,成功解决次数为 349 次,体现了该题目的挑战性和实际应用价值。 ... [详细]
  • 在稀疏直接法视觉里程计中,通过优化特征点并采用基于光度误差最小化的灰度图像线性插值技术,提高了定位精度。该方法通过对空间点的非齐次和齐次表示进行处理,利用RGB-D传感器获取的3D坐标信息,在两帧图像之间实现精确匹配,有效减少了光度误差,提升了系统的鲁棒性和稳定性。 ... [详细]
  • POJ 1696: 空间蚂蚁算法优化与分析
    针对 POJ 1696 的空间蚂蚁算法进行了深入的优化与分析。本研究通过改进算法的时间复杂度和空间复杂度,显著提升了算法的效率。实验结果表明,优化后的算法在处理大规模数据时表现优异,能够有效减少计算时间和内存消耗。此外,我们还对算法的收敛性和稳定性进行了详细探讨,为实际应用提供了可靠的理论支持。 ... [详细]
  • 深入解析Wget CVE-2016-4971漏洞的利用方法与安全防范措施
    ### 摘要Wget 是一个广泛使用的命令行工具,用于从 Web 服务器下载文件。CVE-2016-4971 漏洞涉及 Wget 在处理特定 HTTP 响应头时的缺陷,可能导致远程代码执行。本文详细分析了该漏洞的成因、利用方法以及相应的安全防范措施,包括更新 Wget 版本、配置防火墙规则和使用安全的 HTTP 头。通过这些措施,可以有效防止潜在的安全威胁。 ... [详细]
  • 微软发布紧急安全更新,所有Windows 10版本均面临影响!
    微软于周五紧急发布了两项安全更新,旨在解决Windows 10所有版本中Windows Codecs库和Visual Studio Code应用存在的安全隐患。此次更新是继本周初发布的月度例行安全补丁之外的额外措施,凸显了这些问题的紧迫性和重要性。这些漏洞可能被攻击者利用,导致系统权限提升或远程代码执行等严重后果。建议用户尽快安装更新,以确保系统的安全性。 ... [详细]
  • 内网渗透技术详解:PTH、PTT与PTK在域控环境中的应用及猫盘内网穿透配置
    本文深入探讨了内网渗透技术,特别是PTH、PTT与PTK在域控环境中的应用,并详细介绍了猫盘内网穿透的配置方法。通过这些技术,安全研究人员可以更有效地进行内网渗透测试,解决常见的渗透测试难题。此外,文章还提供了实用的配置示例和操作步骤,帮助读者更好地理解和应用这些技术。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 理工科男女不容错过的神奇资源网站
    十一长假即将结束,你的假期学习计划进展如何?无论你是在家中、思念家乡,还是身处异国他乡,理工科学生都不容错过一些神奇的资源网站。这些网站提供了丰富的学术资料、实验数据和技术文档,能够帮助你在假期中高效学习和提升专业技能。 ... [详细]
  • 进程(Process)是指计算机中程序对特定数据集的一次运行活动,是系统资源分配与调度的核心单元,构成了操作系统架构的基础。在早期以进程为中心的计算机体系结构中,进程被视为程序的执行实例,其状态和控制信息通过任务描述符(task_struct)进行管理和维护。本文将深入探讨进程的概念及其关键数据结构task_struct,解析其在操作系统中的作用和实现机制。 ... [详细]
  • 本研究基于状态空间方法,通过动态可视化技术实现了汉诺塔问题的求解过程,即将n个盘子从A柱移动到C柱。本文提供了一个使用C语言在控制台进行动画绘制的示例,并详细注释了程序逻辑,以帮助读者更好地理解和学习该算法。 ... [详细]
  • 大家好,我们是慢雾安全团队。 ... [详细]
  • IntelliJ IDEA 卡成球了?
    在和同事的一次讨论中发现,对IntelliJIDEA内存采用不同的设置方案,会对IDE的速度和响应能力产生不同的影响。Don’tbeaScroogeandgiveyourIDEso ... [详细]
author-avatar
kkq--_771
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有