1
1
from __future__ import absolute_import
2
2
from __future__ import division
3
+ from __future__ import print_function
3
4
4
5
from pwn import *
5
6
from pwnlib .commandline import common
7
+ from pwnlib .util .misc import which , parse_ldd_output , write
6
8
9
+ from sys import stderr
7
10
from mako .lookup import TemplateLookup , Template
8
11
9
12
parser = common .parser_commands .add_parser (
32
35
os .path .join (printable_data_path , "templates" , "pwnup.mako" ))
33
36
parser .add_argument ('--no-auto' , help = 'Do not automatically detect missing binaries' , action = 'store_false' , dest = 'auto' )
34
37
38
+ def get_docker_image_libraries ():
39
+ """Tries to retrieve challenge libraries from a Docker image built from the Dockerfile in the current working directory.
40
+
41
+ The libraries are retrieved by parsing the output of running ldd on /bin/sh.
42
+ Supports regular Docker images as well as jail images.
43
+ """
44
+ with log .progress ("Extracting challenge libraries from Docker image" ) as progress :
45
+ if not which ("docker" ):
46
+ progress .failure ("docker command not found" )
47
+ return None , None
48
+ # maps jail image name to the root directory of the child image
49
+ jail_image_to_chroot_dir = {
50
+ "pwn.red/jail" : "/srv" ,
51
+ }
52
+ dockerfile = open ("Dockerfile" , "r" ).read ()
53
+ jail = None
54
+ chroot_dir = "/"
55
+ for jail_image in jail_image_to_chroot_dir :
56
+ if re .search (r"^FROM %s" % jail_image , dockerfile , re .MULTILINE ):
57
+ jail = jail_image
58
+ chroot_dir = jail_image_to_chroot_dir [jail_image ]
59
+ break
60
+ try :
61
+ progress .status ("Building image" )
62
+ image_sha = subprocess .check_output (["docker" , "build" , "-q" , "." ], stderr = subprocess .PIPE , shell = False ).decode ().strip ()
63
+
64
+ progress .status ("Retrieving library paths" )
65
+ ldd_command = ["-c" , "chroot %s /bin/sh -c 'ldd /bin/sh'" % chroot_dir ]
66
+ ldd_output = subprocess .check_output ([
67
+ "docker" ,
68
+ "run" ,
69
+ "--rm" ,
70
+ "--entrypoint" ,
71
+ "/bin/sh" ,
72
+ ] + (["--privileged" ] if jail else []) + [
73
+ image_sha ,
74
+ ] + ldd_command ,
75
+ stderr = subprocess .PIPE ,
76
+ shell = False
77
+ ).decode ()
78
+
79
+ libc , ld = None , None
80
+ libc_basename , ld_basename = None , None
81
+ for lib_path in parse_ldd_output (ldd_output ):
82
+ if "libc." in lib_path :
83
+ libc = lib_path
84
+ libc_basename = os .path .basename (lib_path )
85
+ if "ld-" in lib_path :
86
+ ld = lib_path
87
+ ld_basename = os .path .basename (lib_path )
88
+
89
+ if not (libc and ld ):
90
+ progress .failure ("Could not find libraries" )
91
+ return None , None
92
+
93
+ progress .status ("Copying libraries to current directory" )
94
+ for filename , basename in zip ((libc , ld ), (libc_basename , ld_basename )):
95
+ cat_command = ["-c" , "chroot %s /bin/sh -c '/bin/cat %s'" % (chroot_dir , filename )]
96
+ contents = subprocess .check_output ([
97
+ "docker" ,
98
+ "run" ,
99
+ "--rm" ,
100
+ "--entrypoint" ,
101
+ "/bin/sh" ,
102
+ ] + (["--privileged" ] if jail else []) + [
103
+ image_sha
104
+ ] + cat_command ,
105
+ stderr = subprocess .PIPE ,
106
+ shell = False
107
+ )
108
+ write (basename , contents )
109
+
110
+ except subprocess .CalledProcessError as e :
111
+ print (e .stderr .decode ())
112
+ log .error ("docker failed with status: %d" % e .returncode )
113
+
114
+ progress .success ("Retrieved libraries from Docker image" )
115
+ return libc_basename , ld_basename
116
+
35
117
def detect_missing_binaries (args ):
36
118
log .info ("Automatically detecting challenge binaries..." )
37
119
# look for challenge binary, libc, and ld in current directory
38
120
exe , libc , ld = args .exe , args .libc , None
121
+ has_dockerfile = False
39
122
other_files = []
40
- for filename in os .listdir ():
123
+ for filename in os .listdir ("." ):
41
124
if not os .path .isfile (filename ):
42
125
continue
43
126
if not libc and ('libc-' in filename or 'libc.' in filename ):
44
127
libc = filename
45
128
elif not ld and 'ld-' in filename :
46
129
ld = filename
130
+ elif filename == "Dockerfile" :
131
+ has_dockerfile = True
47
132
else :
48
133
if os .access (filename , os .X_OK ):
49
134
other_files .append (filename )
@@ -52,6 +137,9 @@ def detect_missing_binaries(args):
52
137
exe = other_files [0 ]
53
138
elif len (other_files ) > 1 :
54
139
log .warning ("Failed to find challenge binary. There are multiple binaries in the current directory: %s" , other_files )
140
+
141
+ if has_dockerfile and exe and not (libc or ld ):
142
+ libc , ld = get_docker_image_libraries ()
55
143
56
144
if exe != args .exe :
57
145
log .success ("Found challenge binary %r" , exe )
0 commit comments