Skip to content

Commit

Permalink
Merge pull request #11 from phith0n/overlong-encoding
Browse files Browse the repository at this point in the history
Support UTF-8 overlong encoding
  • Loading branch information
phith0n authored Mar 14, 2024
2 parents c09826c + ff2d5c7 commit 9c24390
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 46 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/cicd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
steps:
- uses: actions/setup-go@v2
with:
go-version: '1.17'
go-version: '1.22'

- uses: actions/checkout@v2
- uses: golangci/golangci-lint-action@v2
Expand All @@ -24,7 +24,7 @@ jobs:
needs: [ lint ]
strategy:
matrix:
go-version: [ 1.15.x, 1.16.x, 1.17.x ]
go-version: [ 1.22.x, 1.21.x, 1.20.x, 1.19.x, 1.18.x ]
os: [ ubuntu-latest, macos-latest, windows-latest ]
runs-on: ${{ matrix.os }}
steps:
Expand All @@ -50,7 +50,7 @@ jobs:
fetch-depth: 0
- uses: actions/setup-go@v2
with:
go-version: 1.17
go-version: 1.22
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2
with:
Expand Down
23 changes: 13 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,25 @@ Next, use `github.com/phith0n/zkar/*` in your application:
package main

import (
"fmt"
"github.com/phith0n/zkar/serz"
"io/ioutil"
"log"
"fmt"
"github.com/phith0n/zkar/serz"
"log"
"os"
)

func main() {
data, _ := ioutil.ReadFile("./testcases/ysoserial/CommonsCollections6.ser")
serialization, err := serz.FromBytes(data)
if err != nil {
log.Fatal("parse error")
}
data, _ := os.ReadFile("./testcases/ysoserial/CommonsCollections6.ser")
serialization, err := serz.FromBytes(data)
if err != nil {
log.Fatal("parse error")
}

fmt.Println(serialization.ToString())
fmt.Println(serialization.ToString())
}
```

[Here](serz/tc_utf_test.go) is an example to show how to read an exist payload and modify it to a UTF-8 overlong encoding payload.

## 💻 Command line utility tool

ZKar also provides a command line utility tool that you can use it directly:
Expand Down Expand Up @@ -125,6 +127,7 @@ As the payload is not a valid serialized data stream, it's necessary to tell ZKa
- [x] JDK/JRE 8u20 Gadget supporting
- [ ] Serialization payloads generator
- [ ] An implementation of RMI/LDAP in Go
- [x] Support read/write UTF-8 overlong encoding feature

## ⚖️ License

Expand Down
21 changes: 14 additions & 7 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
module github.com/phith0n/zkar

go 1.16
go 1.18

require (
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
github.com/kr/pretty v0.1.0 // indirect
github.com/phith0n/litter v1.5.3
github.com/stretchr/testify v1.7.0
github.com/thoas/go-funk v0.9.0
github.com/urfave/cli/v2 v2.3.0
github.com/stretchr/testify v1.9.0
github.com/thoas/go-funk v0.9.3
github.com/urfave/cli/v2 v2.27.1
)

require (
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/kr/pretty v0.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
32 changes: 14 additions & 18 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand All @@ -14,24 +12,22 @@ github.com/phith0n/litter v1.5.3 h1:HJBgdlibJT57lmkT6XZPeWQCuDGKf9QkKHgnJJ98+io=
github.com/phith0n/litter v1.5.3/go.mod h1:T2hptLevnpc+lnUskkc/7yF6wvuej1A6fuMfP2uGbZ0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/thoas/go-funk v0.9.0 h1:Yzu8aTjTb1sqHZzSZLBt4qaZrFfjNizhA7IfnefjEzo=
github.com/thoas/go-funk v0.9.0/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q=
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/thoas/go-funk v0.9.3 h1:7+nAEx3kn5ZJcnDm2Bh23N2yOtweO14bi//dvRtgLpw=
github.com/thoas/go-funk v0.9.3/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q=
github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho=
github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
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
}
51 changes: 51 additions & 0 deletions serz/tc_utf_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package serz

import (
"os"
"testing"

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

// TestCC6WithOverlongEncoding show how to read an exist payload and modify it to a UTF-8 overlong encoding payload.
func TestCC6WithOverlongEncoding(t *testing.T) {
// read original CommonsCollections6 payload
data, err := os.ReadFile("../testcases/ysoserial/CommonsCollections6.ser")
require.NoError(t, err)
ser, err := FromBytes(data)
require.NoError(t, err)

// enable UTF-8 overlong encoding feature
err = ser.Walk(func(obj Object) error {
if u, ok := obj.(*TCUtf); ok {
u.SetOverlongSize(OverlongEncodingTwoBytes)
}

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

// generate new payload
data2 := ser.ToBytes()

// read new payload
_, err = FromBytes(data2)
require.NoError(t, err)
}

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")))
}

0 comments on commit 9c24390

Please sign in to comment.