Skip to content

Commit

Permalink
to support overlong encoding
Browse files Browse the repository at this point in the history
  • Loading branch information
phith0n committed Mar 14, 2024
1 parent c09826c commit 3580761
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 8 deletions.
79 changes: 71 additions & 8 deletions serz/tc_utf.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,35 @@ import (
"github.com/phith0n/zkar/commons"
)

type OverlongOption int

const (
OverlongEncodingTwoBytes OverlongOption = 2
OverlongEncodingThreeBytes OverlongOption = 3
)

type TCUtf struct {
Data string

OverlongSize OverlongOption
}

func (u *TCUtf) ToBytes() []byte {
var bs []byte
var length = len(u.Data)
if length <= 0xFFFF {
bs = commons.NumberToBytes(uint16(len(u.Data)))
var data []byte
if u.OverlongSize == OverlongEncodingTwoBytes || u.OverlongSize == OverlongEncodingThreeBytes {
data = toOverlongEncoding([]byte(u.Data), u.OverlongSize)
} else {
bs = commons.NumberToBytes(uint64(len(u.Data)))
data = []byte(u.Data)
}

var length []byte
if len(data) <= 0xFFFF {
length = commons.NumberToBytes(uint16(len(data)))
} else {
length = commons.NumberToBytes(uint64(len(data)))
}

return append(bs, []byte(u.Data)...)
return append(length, data...)
}

func (u *TCUtf) ToString() string {
Expand All @@ -41,6 +56,10 @@ func (u *TCUtf) Walk(callback WalkCallback) error {
return nil
}

func (u *TCUtf) SetOverlongSize(size OverlongOption) {
u.OverlongSize = size
}

func readUTF(stream *ObjectStream) (*TCUtf, error) {
var bs []byte
var err error
Expand All @@ -59,7 +78,7 @@ func readUTF(stream *ObjectStream) (*TCUtf, error) {
}

return &TCUtf{
Data: string(data),
Data: string(fromOverlongEncoding(data)),
}, nil
}

Expand All @@ -81,6 +100,50 @@ func readLongUTF(stream *ObjectStream) (*TCUtf, error) {
}

return &TCUtf{
Data: string(data),
Data: string(fromOverlongEncoding(data)),
}, nil
}

func toOverlongEncoding(data []byte, size OverlongOption) []byte {
var bs []byte
for _, ch := range data {
if size == OverlongEncodingTwoBytes {
bs = append(bs, ((ch>>6)&0b11111)|0b11000000)
bs = append(bs, (ch&0b111111)|0b10000000)
} else {
bs = append(bs, 0b11100000)
bs = append(bs, (ch>>6&0b111111)|0b10000000)
bs = append(bs, (ch&0b111111)|0b10000000)
}
}

return bs
}

func fromOverlongEncoding(data []byte) []byte {
var rs []byte
for i := 0; i < len(data); {
b1 := data[i]
i++
if i < len(data) && b1>>5 == 0b110 {
b2 := data[i]
if b1>>1 == 0b1100000 && b2>>6 == 0b10 {
rs = append(rs, (b2&0b111111)|(b1<<6))
i++
continue
}
} else if i+1 < len(data) && b1>>4 == 0b1110 {
b2 := data[i]
b3 := data[i+1]

if b1 == 0b11100000 && b2>>1 == 0b1000000 && b3>>6 == 0b10 {
rs = append(rs, (b3&0b111111)|(b2<<6))
i += 2
continue
}
}

rs = append(rs, b1)
}
return rs
}
46 changes: 46 additions & 0 deletions serz/tc_utf_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package serz

import (
"os"
"testing"

"github.com/stretchr/testify/require"
)

func TestToOverlongEncoding(t *testing.T) {
require.Equal(t, []byte("\xC0\xAE"), toOverlongEncoding([]byte("."), OverlongEncodingTwoBytes))
require.Equal(t, []byte("\xE0\x80\xAE"), toOverlongEncoding([]byte("."), OverlongEncodingThreeBytes))
require.Equal(t, []byte("\xc1\xaf\xc1\xb2\xc1\xa7\xc0\xae\xc1\xa5\xc1\xb8\xc1\xa1\xc1\xad\xc1\xb0\xc1"+
"\xac\xc1\xa5\xc0\xae\xc1\x85\xc1\xb6\xc1\xa9\xc1\xac"),
toOverlongEncoding([]byte("org.example.Evil"), OverlongEncodingTwoBytes))

require.Equal(t, []byte("."), fromOverlongEncoding(toOverlongEncoding([]byte("."), OverlongEncodingTwoBytes)))
require.Equal(t, []byte("."), fromOverlongEncoding(toOverlongEncoding([]byte("."), OverlongEncodingThreeBytes)))
require.Equal(t, []byte("org.example.Evil"), fromOverlongEncoding(toOverlongEncoding([]byte("org.example.Evil"), OverlongEncodingTwoBytes)))
require.Equal(t, []byte("org.example.Evil"), fromOverlongEncoding(toOverlongEncoding([]byte("org.example.Evil"), OverlongEncodingThreeBytes)))

require.Equal(t, []byte{0xC0, 0xFF}, fromOverlongEncoding([]byte{0xC0, 0xFF}))
require.Equal(t, []byte{0xE0, 0xAE, 0x38}, fromOverlongEncoding([]byte{0xE0, 0xAE, 0x38}))
require.Equal(t, []byte("org.example.Evil"), fromOverlongEncoding([]byte("org.example.Evil")))
}

func TestCC6WithOverlongEncoding(t *testing.T) {
data, err := os.ReadFile("/home/owen/app/ysoserial/cc6.ser")
require.NoError(t, err)

ser, err := FromBytes(data)

require.NoError(t, err)

err = ser.Walk(func(obj Object) error {
if u, ok := obj.(*TCUtf); ok {
u.SetOverlongSize(OverlongEncodingTwoBytes)
}

return nil
})
require.NoError(t, err)

err = os.WriteFile("/home/owen/app/ysoserial/cc6-2.ser", ser.ToBytes(), 0o644)
require.NoError(t, err)
}

0 comments on commit 3580761

Please sign in to comment.