{"id":28437003,"url":"https://github.com/ronin-rb/ronin-post_ex","last_synced_at":"2025-09-05T03:43:47.320Z","repository":{"id":63149269,"uuid":"436358548","full_name":"ronin-rb/ronin-post_ex","owner":"ronin-rb","description":"A Ruby API for Post-Exploitation","archived":false,"fork":false,"pushed_at":"2025-02-02T22:37:03.000Z","size":653,"stargazers_count":5,"open_issues_count":9,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-06T17:49:34.377Z","etag":null,"topics":["hacktoberfest","post-exploitation","ruby"],"latest_commit_sha":null,"homepage":"https://ronin-rb.dev","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ronin-rb.png","metadata":{"files":{"readme":"README.md","changelog":"ChangeLog.md","contributing":null,"funding":null,"license":"COPYING.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"open_collective":"ronin-rb","patreon":"roninrb"}},"created_at":"2021-12-08T18:53:11.000Z","updated_at":"2025-06-17T12:14:28.000Z","dependencies_parsed_at":"2023-11-23T22:32:13.402Z","dependency_job_id":"766f6e56-73f4-4454-944e-f25db0fc0f16","html_url":"https://github.com/ronin-rb/ronin-post_ex","commit_stats":{"total_commits":496,"total_committers":1,"mean_commits":496.0,"dds":0.0,"last_synced_commit":"e923054dafd76d2cd7c801a450be8bbac91e463b"},"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/ronin-rb/ronin-post_ex","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ronin-rb%2Fronin-post_ex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ronin-rb%2Fronin-post_ex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ronin-rb%2Fronin-post_ex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ronin-rb%2Fronin-post_ex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ronin-rb","download_url":"https://codeload.github.com/ronin-rb/ronin-post_ex/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ronin-rb%2Fronin-post_ex/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273709024,"owners_count":25153730,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-05T02:00:09.113Z","response_time":402,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hacktoberfest","post-exploitation","ruby"],"created_at":"2025-06-05T23:08:26.581Z","updated_at":"2025-09-05T03:43:42.306Z","avatar_url":"https://github.com/ronin-rb.png","language":"Ruby","funding_links":["https://opencollective.com/ronin-rb","https://patreon.com/roninrb"],"categories":[],"sub_categories":[],"readme":"# ronin-post_ex\n\n[![CI](https://github.com/ronin-rb/ronin-post_ex/actions/workflows/ruby.yml/badge.svg)](https://github.com/ronin-rb/ronin-post_ex/actions/workflows/ruby.yml)\n[![Code Climate](https://codeclimate.com/github/ronin-rb/ronin-post_ex.svg)](https://codeclimate.com/github/ronin-rb/ronin-post_ex)\n[![Gem Version](https://badge.fury.io/rb/ronin-post_ex.svg)](https://badge.fury.io/rb/ronin-post_ex)\n\n* [Website](https://ronin-rb.dev/)\n* [Source](https://github.com/ronin-rb/ronin-post_ex)\n* [Issues](https://github.com/ronin-rb/ronin-post_ex/issues)\n* [Documentation](https://ronin-rb.dev/docs/ronin-post_ex/frames)\n* [Discord](https://discord.gg/6WAb3PsVX9) |\n  [Mastodon](https://infosec.exchange/@ronin_rb)\n\n## Description\n\nronin-post_ex is a Ruby API for Post-Exploitation.\n\nThis library is used by [ronin-payloads], [ronin-c2], and [ronin-exploits]\nto provide a Post-Exploitation API around payloads, C2 sessions, or even\nexploits.\n\nronin-post_ex is part of the [ronin-rb] project, a [Ruby] toolkit for security\nresearch and development.\n\n## Features\n\n* Provides an standard API for interacting with compromised systems:\n  * {Ronin::PostEx::System} - allows interacting with a remote system.\n  * {Ronin::PostEx::System::FS} - allows interacting with the file-system.\n  * {Ronin::PostEx::System::Process} - allows manipulating the current process\n    or child processes.\n  * {Ronin::PostEx::System::Shell} - allows interacting with an interactive\n    shell..\n  * {Ronin::PostEx::RemoteFile} - allows reading/writing files.\n  * {Ronin::PostEx::RemoteDir} - allows reading the contents of directories.\n  * {Ronin::PostEx::RemoteProcess} - allows reading/writing to an running\n    command.\n* Provides many different session handlers:\n  * {Ronin::PostEx::Sessions::BindShell} - interacts with bind shells.\n  * {Ronin::PostEx::Sessions::ReverseShell} - interacts with reverse shells.\n  * Supports defining [custom session handler classes](#custom-session-classes).\n* Provides interactive RPC and command-line shells for interacting with\n  compromised systems.\n* Currently only supports interacting with Linux/BSD/UNIX systems.\n\n## Limitations\n\n* Does not currently support Windows systems.\n* Does not fully support bidirectional fully interactive shell commands.\n\n## Examples\n\n### Bind Shell\n\n```ruby\nsession = Ronin::PostEx::Sessions::BindShell.connect(host,port)\nsystem  = Ronin::PostEx::System.new(session)\n\nsystem.shell.ls('/')\n# =\u003e \"bin\\nboot\\ndev\\netc\\nhome\\nlib\\nlib64\\nlost+found\\nmedia\\nmnt\\nopt\\nproc\\nroot\\nrun\\nsbin\\nsnap\\nsrv\\nsys\\ntmp\\nusr\\nvar\\n\"\n```\n\n### Reverse Shell\n\n```ruby\nsession = Ronin::PostEx::Sessions::ReverseShell.listen(host,port)\nsystem  = Ronin::PostEx::System.new(session)\n\nsystem.shell.ls('/')\n# =\u003e \"bin\\nboot\\ndev\\netc\\nhome\\nlib\\nlib64\\nlost+found\\nmedia\\nmnt\\nopt\\nproc\\nroot\\nrun\\nsbin\\nsnap\\nsrv\\nsys\\ntmp\\nusr\\nvar\\n\"\n```\n\n### System\n\nInteract with the system's remote files as if they were local files:\n\n```ruby\nfile = system.fs.open('/etc/passwd')\n\nfile.each_line do |line|\n  user, x, uid, gid, name, home_dir, shell = line.split(':')\n\n  puts \"User Detected: #{user} (id=#{uid})\"\nend\n```\n\nGet information about the current process:\n\n```ruby\nsystem.process.pid\n# =\u003e 1234\n\nsystem.process.getuid\n# =\u003e 1001\n\nsystem.process.environ\n# =\u003e {\"HOME\"=\u003e\"...\", \"PATH\"=\u003e\"...\", ...}\n```\n\nExecute commands on the remote system:\n\n```ruby\nsystem.shell.ls('/')\n# =\u003e \"bin\\nboot\\ndev\\netc\\nhome\\nlib\\nlib64\\nlost+found\\nmedia\\nmnt\\nopt\\nproc\\nroot\\nrun\\nsbin\\nsnap\\nsrv\\nsys\\ntmp\\nusr\\nvar\\n\"\n\nsystem.shell.exec(\"find -type f -name '*.xls' /srv\") do |path|\n  puts \"Found XLS file: #{path}\"\nend\n```\n\nSpawn an interactive command shell:\n\n```ruby\nsystem.shell.interact\n$\n```\n\nSpawn an interactive post-exploitation system shell:\n\n```ruby\nsystem.interact\n```\n```\nronin-post_ex\u003e help\n  help [COMMAND]                                                                \tPrints the list of commands or additional help\n  quit                                                                          \tExits the shell\n  fs.chdir DIR                                                                  \tChanges the current working directory\n  fs.pwd                                                                        \tPrints the current working directory\n  fs.readfile FILE                                                              \tReads the contents of a given FILE\n  fs.readlink SYMLINK                                                           \tReads the destination path of a symlink\n  fs.readdir DIR                                                                \tReads the contents of a given directory\n  fs.hexdump FILE                                                               \tHexdumps a given file\n  fs.copy SRC DEST                                                              \tCopies the SRC file to the DEST path\n  fs.unlink FILE                                                                \tDeletes a given file\n  fs.rmdir DIR                                                                  \tRemoves a given directory\n  fs.mv SRC DEST                                                                \tMoves or renames a given file or directory\n  fs.link SRC DEST                                                              \tCreates a link from the source to the destination\n  fs.chown USER PATH                                                            \tChanges the owner of a given file or directory\n  fs.chgrp GROUP PATH                                                           \tChanges the group of a given file or directory\n  fs.chmod MODE PATH                                                            \tChanges the permission mode of a given file or directory\n  fs.stat PATH                                                                  \tPrints file system information about a given file or directory\n  files                                                                         \tLists opened files\n  file.open PATH [MODE]                                                         \tOpens a file for reading or writing\n  file.seek FILE_ID POS [SEEK_SET | SEEK_CUR | SEEK_END | SEEK_DATA | SEEK_HOLE]\tSeeks to a position within the file\n  file.read FILE_ID LENGTH                                                      \tReads LENGTH of data from an opened file\n  file.write FILE_ID DATA                                                       \tWrites data to an opened file\n  file.close FILE_ID                                                            \tCloses an open file\n  process.pid                                                                   \tPrints the process'es PID\n  process.ppid                                                                  \tPrints the process'es PPID\n  process.uid                                                                   \tPrints the process'es UID\n  process.setuid UID                                                            \tSets the process'es UID\n  process.euid EUID                                                             \tPrints the process'es EUID\n  process.seteuid EUID                                                          \tSets the process'es EUID\n  process.gid COMMAND                                                           \tPrints the process'es GID\n  process.setgid GID                                                            \tSets the process'es GID\n  process.egid                                                                  \tPrints the process'es EGID\n  process.setegid EGID                                                          \tSets the process'es EGID\n  process.sid                                                                   \tPrints the process'es SID\n  process.setsid SID                                                            \tPrints the process'es SID\n  process.env                                                                   \tPrints the process'es environment variables\n  process.getenv NAME                                                           \tPrints an environment variable from the process\n  process.setenv NAME=VALUE                                                     \tSets an environment variable for the process\n  process.unsetenv NAME                                                         \tUnsets an environment variable for the process\n  process.kill PID [SIGNAL]                                                     \tKills a process\n  process.spawn PROGRAM [ARGS ...]                                              \tSpawns a new process\n  shell.exec COMMAND                                                            \tExecutes a command in the shell\n  shell                                                                         \tSpawns an interactive command shell\n  sys.time                                                                      \tPrints the system's current time\n  sys.hostname                                                                  \tPrints the system's hostname\nronin-post_ex\u003e \n```\n\n### Custom Session Classes\n\nDefine a custom session class which defines the\n[Post-Exploitation Session API methods][API Spec]:\n\n```ruby\nrequire 'ronin/post_ex/sessions/session'\nrequire 'base64'\n\nclass MyRatSession \u003c Ronin::PostEx::Sessions::Session\n\n  def initialize(socket)\n    @socket = socket\n  end\n\n  def send_command(name,*args)\n    # send the command line\n    @socket.puts(\"#{name} #{args.join(' ')}\")\n\n    # read and Base64 decode the response line\n    Base64.strict_decode64(@socket.gets(chomp: true))\n  end\n\n  def shell_exec(command)\n    send_command('EXEC',command)\n  end\n\n  def fs_readfile(path)\n    send_command('READ',path)\n  end\n\n  def process_pid\n    send_command('PID').to_i\n  end\n\n  def process_getuid\n    send_command('UID').to_i\n  end\n\n  def process_environ\n    Hash[\n      send_command('ENV').each_line(chomp: true).map { |line|\n        line.split('=',2)\n      }\n    ]\n  end\n\nend\n\nsession = MyRatSession.new(socket)\nsystem  = Ronin::PostEx::System.new(session)\n```\n\n## Requirements\n\n* [Ruby] \u003e= 3.0.0\n* [base64] ~\u003e 0.1\n* [fake_io] ~\u003e 0.1\n* [hexdump] ~\u003e 1.0\n* [ronin-core] ~\u003e 0.1\n\n## Install\n\n```shell\n$ gem install ronin-post_ex\n```\n\n### Gemfile\n\n```ruby\ngem 'ronin-post_ex', '~\u003e 0.1'\n```\n\n### gemspec\n\n```ruby\ngem.add_dependency 'ronin-post_ex', '~\u003e 0.1'\n```\n\n## Development\n\n1. [Fork It!](https://github.com/ronin-rb/ronin-post_ex/fork)\n2. Clone It!\n3. `cd ronin-post_ex/`\n4. `bundle install`\n5. `git checkout -b my_feature`\n6. Code It!\n7. `bundle exec rake spec`\n8. `git push origin my_feature`\n\n## License\n\nCopyright (c) 2007-2024 Hal Brodigan (postmodern.mod3 at gmail.com)\n\nronin-post_ex is free software: you can redistribute it and/or modify\nit under the terms of the GNU Lesser General Public License as published\nby the Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nronin-post_ex is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU Lesser General Public License for more details.\n\nYou should have received a copy of the GNU Lesser General Public License\nalong with ronin-post_ex.  If not, see \u003chttps://www.gnu.org/licenses/\u003e.\n\n[Ruby]: https://www.ruby-lang.org\n[ronin-rb]: https://ronin-rb.dev\n\n[base64]: https://github.com/ruby/base64#readme\n[fake_io]: https://github.com/postmodern/fake_io.rb#readme\n[hexdump]: https://github.com/postmodern/hexdump.rb#readme\n[ronin-core]: https://github.com/ronin-rb/ronin-core#readme\n[ronin-payloads]: https://github.com/ronin-rb/ronin-payloads#readme\n[ronin-c2]: https://github.com/ronin-rb/ronin-c2#readme\n[ronin-exploits]: https://github.com/ronin-rb/ronin-exploits#readme\n\n[API Spec]: https://github.com/ronin-rb/ronin-post_ex/blob/main/API_SPEC.md\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fronin-rb%2Fronin-post_ex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fronin-rb%2Fronin-post_ex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fronin-rb%2Fronin-post_ex/lists"}