mirror of
https://github.com/Gallopsled/pwntools.git
synced 2026-11-08 01:58:16 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
74f475170d | ||
|
|
0dc0a9acc0 | ||
|
|
774ed3b85e | ||
|
|
292b81af17 | ||
|
|
90056fbeca | ||
|
|
60df8107c0 | ||
|
|
7467402ecf | ||
|
|
80e12c7031 | ||
|
|
f4159bdad4 | ||
|
|
26e6bce81a | ||
|
|
6af09645e7 | ||
|
|
146348f514 | ||
|
|
fe6619b336 | ||
|
|
5ae13e8c8c | ||
|
|
67473560c7 | ||
|
|
1cb0502157 | ||
|
|
9604f7847e | ||
|
|
c888a8cbe0 | ||
|
|
9f9d884790 | ||
|
|
39bc5808ea | ||
|
|
31f7c61c1f | ||
|
|
2a73356c78 | ||
|
|
25c84daa8a | ||
|
|
3ff7a9e940 | ||
|
|
e50b978398 | ||
|
|
d689805690 | ||
|
|
953e73aa37 | ||
|
|
ee9f9fa7de | ||
|
|
35789287d8 | ||
|
|
7a1ab829eb | ||
|
|
46a1c44fc9 | ||
|
|
899baec704 | ||
|
|
932cb57bf9 | ||
|
|
6a61617c73 | ||
|
|
6944b664e8 | ||
|
|
ab8879afa3 | ||
|
|
515f678f2d | ||
|
|
c3afdd681d | ||
|
|
5d537a6189 | ||
|
|
9ba966ddba | ||
|
|
6ea5722f5b | ||
|
|
4e24f665b8 | ||
|
|
34cedc96d8 | ||
|
|
e8065440c2 | ||
|
|
de34906b4c | ||
|
|
e89a9b66ac | ||
|
|
64acece61b | ||
|
|
bb9004c298 | ||
|
|
712295f3c5 | ||
|
|
cca1083f0b | ||
|
|
9dacd1b5d9 | ||
|
|
d9f5a5b009 | ||
|
|
74a5876c0d | ||
|
|
9d6b4881fe | ||
|
|
91025408a4 | ||
|
|
b53e58a840 | ||
|
|
438096f97f | ||
|
|
7bab49e7b9 | ||
|
|
412d345964 | ||
|
|
b088f46988 | ||
|
|
8f3839d69e | ||
|
|
5a81e71368 | ||
|
|
1577263334 | ||
|
|
7ad5a4e34e | ||
|
|
513682373e | ||
|
|
df7c1fef9d | ||
|
|
559ffa7c9e | ||
|
|
2512026b3c | ||
|
|
518ed71488 | ||
|
|
26d60cbf63 | ||
|
|
b234b319df | ||
|
|
6577f24d3a | ||
|
|
4a7ff431b9 | ||
|
|
716c67d993 | ||
|
|
91768424ba | ||
|
|
af2f8b4bf4 | ||
|
|
9ed8ab6d4f | ||
|
|
19f7268701 | ||
|
|
e4d919d6bf | ||
|
|
93d9a2cb5e | ||
|
|
69f8cc2c47 | ||
|
|
ab0ac00c73 | ||
|
|
d87ab3ac65 | ||
|
|
23cd5cb819 | ||
|
|
47d5cf7da1 | ||
|
|
a7263688db | ||
|
|
630c4651fa | ||
|
|
54c47b3daa | ||
|
|
bb25140807 | ||
|
|
ebbe917713 | ||
|
|
b62804eff6 | ||
|
|
ec98dc1246 | ||
|
|
92ad1a4933 | ||
|
|
7cd3c7b300 | ||
|
|
3e163e9cf2 | ||
|
|
267c6cc15a | ||
|
|
5831796f6f | ||
|
|
c438893d7e | ||
|
|
3e33180655 | ||
|
|
e09543c098 | ||
|
|
1a94acab67 | ||
|
|
6263a347bd | ||
|
|
a344047348 | ||
|
|
4aa96b48ba | ||
|
|
6f2598aee0 | ||
|
|
3f42ce8636 | ||
|
|
901f3eddb1 | ||
|
|
5180230f04 | ||
|
|
1ab07de033 | ||
|
|
5936d0f565 | ||
|
|
e3fd03458a | ||
|
|
55016fb416 | ||
|
|
08b316098b | ||
|
|
a27cb1c168 | ||
|
|
d923729dfb | ||
|
|
db75ecb897 | ||
|
|
0dc2949790 | ||
|
|
52b8f4fa29 | ||
|
|
89a848b51f | ||
|
|
672b4dd090 | ||
|
|
094e44fd65 | ||
|
|
4552624883 | ||
|
|
b171f1e2e3 | ||
|
|
85523e6d8a | ||
|
|
8b761fc0e3 | ||
|
|
b83db46c34 | ||
|
|
40c1796fc4 | ||
|
|
984d54d9b2 | ||
|
|
3cbc527deb | ||
|
|
1482fb7545 | ||
|
|
7ed6f5fe6b | ||
|
|
fd5a7fea68 | ||
|
|
8953dc3d5c | ||
|
|
fda1821fd9 | ||
|
|
f7568b47b3 | ||
|
|
2ccd36ca7f | ||
|
|
9062360041 | ||
|
|
3f9c192a5e | ||
|
|
b8e902b611 | ||
|
|
d586d6f660 | ||
|
|
6709a4f747 | ||
|
|
1a4a1e11ba | ||
|
|
f82c0aa3a2 | ||
|
|
646ca1eb26 | ||
|
|
8055ec98ce | ||
|
|
aa1f3f7f5a | ||
|
|
043627a56d | ||
|
|
a40a0ecab4 | ||
|
|
bbe20c9748 | ||
|
|
c700f9194c | ||
|
|
71a3e43be3 | ||
|
|
267b9990c2 | ||
|
|
cfee8e0b24 | ||
|
|
32a767d469 | ||
|
|
eaea783e2a | ||
|
|
9bda42e45d | ||
|
|
f4b3469fb4 | ||
|
|
0903f9055b | ||
|
|
0a23a457c5 | ||
|
|
7fe6dd0e8e | ||
|
|
4772a22fed | ||
|
|
42692c685e | ||
|
|
aa3acc162f | ||
|
|
676e6869a0 | ||
|
|
9b50163760 | ||
|
|
289109f499 | ||
|
|
e90fb15596 | ||
|
|
3b9c0db1a2 | ||
|
|
dd7a67b6d7 | ||
|
|
ad87c17f73 | ||
|
|
2714a30488 | ||
|
|
ac386877d1 | ||
|
|
4f08b6d79c | ||
|
|
348f6dfbe7 | ||
|
|
80219df5cc | ||
|
|
065c79d29c | ||
|
|
310f186e5f | ||
|
|
bac44542ed | ||
|
|
a54e697b55 | ||
|
|
5f1294af09 | ||
|
|
7cc4ced8d6 | ||
|
|
5c72d62c90 | ||
|
|
925cb43024 | ||
|
|
6f42e1c337 | ||
|
|
8a7bb9b9f4 | ||
|
|
512c2544b5 | ||
|
|
8120b5c037 | ||
|
|
55456814fc | ||
|
|
eb3e3797cd | ||
|
|
3416b7c949 | ||
|
|
dc9882abe7 | ||
|
|
664622fa07 | ||
|
|
930f2a4a32 | ||
|
|
10ef77b997 | ||
|
|
ecba8e4b38 | ||
|
|
0d3b97b378 | ||
|
|
33945f6885 | ||
|
|
b7ddfa995e | ||
|
|
3b2be2b2a7 | ||
|
|
0a3ac521ad | ||
|
|
1f72e45eaf | ||
|
|
421a3093fc | ||
|
|
d08fc6d3a0 | ||
|
|
dd6931907a | ||
|
|
de3a68d8b4 | ||
|
|
93b828ff97 | ||
|
|
326dd83321 | ||
|
|
f8bb49c78f | ||
|
|
510e247034 | ||
|
|
4d529cd543 | ||
|
|
e021f57806 | ||
|
|
b6cfec6284 | ||
|
|
4834032b14 | ||
|
|
1273552189 | ||
|
|
ef1e3cfb97 | ||
|
|
e9fc0125a6 | ||
|
|
81239be429 | ||
|
|
f4b0e3a5b9 | ||
|
|
1f1a6667a1 | ||
|
|
464e9e54e1 | ||
|
|
a786a58db7 | ||
|
|
bc471d13f9 | ||
|
|
6af464fc0e | ||
|
|
29e38a7d49 | ||
|
|
658589704a | ||
|
|
71855ebd2f | ||
|
|
393751351b | ||
|
|
c8a690d617 | ||
|
|
8b8a50b580 | ||
|
|
3b07dfe7cc | ||
|
|
5877f8e97e | ||
|
|
4ebcbee34b | ||
|
|
d25d62c126 | ||
|
|
5392611ed5 | ||
|
|
7c139c7179 | ||
|
|
da9ce55dfd | ||
|
|
9d394e0df1 | ||
|
|
f962d2bd21 | ||
|
|
667d290d9b | ||
|
|
766c4d8a7f | ||
|
|
189b1fb3c2 | ||
|
|
6c1b882b40 | ||
|
|
0c76348072 | ||
|
|
2f7d78bc64 | ||
|
|
646723fa8e | ||
|
|
e77915fba6 | ||
|
|
a02e8da1ea | ||
|
|
6979cb0d2b | ||
|
|
bc8942006b | ||
|
|
07c7b51f25 | ||
|
|
ee655cac60 | ||
|
|
b668815323 | ||
|
|
a26a1a1f35 | ||
|
|
ab42519e26 | ||
|
|
59b44b4fe6 | ||
|
|
f4f21f147b | ||
|
|
c06822571f | ||
|
|
383a4f4596 | ||
|
|
25d63da30e | ||
|
|
dd2ad30a51 | ||
|
|
d160f9b7c9 | ||
|
|
0bdbc2b8c3 | ||
|
|
d0c4d8488e | ||
|
|
f3968afbbb | ||
|
|
2d04acb867 | ||
|
|
62842e20f0 | ||
|
|
c929217947 | ||
|
|
ff08a859f8 | ||
|
|
ba24b440c5 | ||
|
|
b31adf27d0 | ||
|
|
20d27c651a | ||
|
|
ba7911651e | ||
|
|
cded6cda47 | ||
|
|
25941b52bb | ||
|
|
b79a750af6 | ||
|
|
eede2e2e1d | ||
|
|
2a59f5cf4c | ||
|
|
a3e82e27bb | ||
|
|
368a708663 | ||
|
|
4a7de306f0 | ||
|
|
69bbd0839a | ||
|
|
475ffa632e | ||
|
|
06db497901 | ||
|
|
5106c4eb75 | ||
|
|
08b7b190a7 | ||
|
|
8259d07207 | ||
|
|
ad2eb77cfa | ||
|
|
ec04c860c0 | ||
|
|
ffe4cf6807 | ||
|
|
673073f08d | ||
|
|
0e45f23af8 | ||
|
|
31cd98affe | ||
|
|
3e4a1bcc72 | ||
|
|
85c3074574 | ||
|
|
178e64a4f7 | ||
|
|
179476604e | ||
|
|
fc6e00d9f0 | ||
|
|
8b1f1dce84 | ||
|
|
8345bc3824 | ||
|
|
300f8e0c1a | ||
|
|
9ace73a977 | ||
|
|
fb16e158ec | ||
|
|
e519874947 | ||
|
|
2e90d05156 | ||
|
|
b6e3d5d8c5 | ||
|
|
0726d8d339 | ||
|
|
bd5a368754 | ||
|
|
602efd2790 | ||
|
|
2f7f0de984 | ||
|
|
45d2c11535 | ||
|
|
16b507e197 | ||
|
|
53f041a4d2 | ||
|
|
b2a5b76cf7 | ||
|
|
9cb438842c | ||
|
|
14f717b7b4 | ||
|
|
f792407c19 | ||
|
|
9c2f0f4e89 | ||
|
|
eb0bb6ea8d | ||
|
|
f46112e873 | ||
|
|
975844d83d | ||
|
|
466c0e4179 | ||
|
|
17e4f01976 | ||
|
|
fecd6f8222 | ||
|
|
7ba3a1b32f | ||
|
|
d1edd275d9 | ||
|
|
8f012947e9 | ||
|
|
36b05bac2b | ||
|
|
cb4991c41d | ||
|
|
65f18b6091 | ||
|
|
48616c633d | ||
|
|
323975f343 | ||
|
|
f65c258956 | ||
|
|
c928a0425e | ||
|
|
f5e16d3db6 | ||
|
|
d55874a6d3 | ||
|
|
0426d498d9 | ||
|
|
fefd48f341 | ||
|
|
132f48e6ee | ||
|
|
e205e17b6d | ||
|
|
d0267f3ee7 | ||
|
|
0c8006ca4e | ||
|
|
bd88c92991 | ||
|
|
12f1bb9126 | ||
|
|
3fa2c659fd | ||
|
|
a2c67e5075 | ||
|
|
54e722819b | ||
|
|
179a0656f5 | ||
|
|
58b2e36a1b | ||
|
|
24ae51dae4 | ||
|
|
14e68ec226 | ||
|
|
485dcede2c | ||
|
|
50acdbbe41 | ||
|
|
4e0e9d2acb | ||
|
|
bc7c8cd423 | ||
|
|
a8446bef47 | ||
|
|
afdcdec577 | ||
|
|
c13ff2cb08 | ||
|
|
a12d0b6a4c | ||
|
|
3dd6045488 | ||
|
|
cca9782424 | ||
|
|
5ce5339ab5 | ||
|
|
0cead77039 | ||
|
|
1d59a90fa8 | ||
|
|
ac017d97dc | ||
|
|
b584ca349a | ||
|
|
8b30700f92 | ||
|
|
7ed118763b | ||
|
|
5a370162e5 | ||
|
|
253ab78e4c | ||
|
|
e997c17397 | ||
|
|
0acc8ee499 | ||
|
|
d39f9a145e | ||
|
|
f14e0e5652 | ||
|
|
aaa83983ad | ||
|
|
1b76a27bd5 | ||
|
|
87491bf6dc | ||
|
|
b30835ec5b | ||
|
|
1241073391 | ||
|
|
cfcd79e169 | ||
|
|
706a784904 | ||
|
|
70c96330de | ||
|
|
cae3cddc07 | ||
|
|
5373dcdeed | ||
|
|
5d4bf3db6c | ||
|
|
fbfa54ad61 | ||
|
|
b323264032 | ||
|
|
332c9d2031 | ||
|
|
036397c861 | ||
|
|
dcf03fd44d | ||
|
|
df54bf2bb3 | ||
|
|
386e68691f | ||
|
|
2c841eaa21 | ||
|
|
22f170abc7 | ||
|
|
350610fbee | ||
|
|
c7b3852eae | ||
|
|
eaf6402198 | ||
|
|
d2c6184a00 | ||
|
|
e5645e7b53 | ||
|
|
09dbe0a54d | ||
|
|
0bd0de78f9 | ||
|
|
546061e577 | ||
|
|
5ebc8b5bb7 | ||
|
|
b83a6c7db8 | ||
|
|
5d9792fb4c | ||
|
|
1c54e347f2 | ||
|
|
2f597f41d4 | ||
|
|
7545dafffb | ||
|
|
3acec5421f | ||
|
|
620364dd1d | ||
|
|
b441cf967a | ||
|
|
76c21548db | ||
|
|
ad71d9235b | ||
|
|
2e5f8061b2 | ||
|
|
099404277e | ||
|
|
30c34b785a | ||
|
|
6c304d3511 | ||
|
|
dc297e17ae | ||
|
|
fa402ceb57 | ||
|
|
483adb8e2d | ||
|
|
76fe04e356 | ||
|
|
82312baba0 | ||
|
|
d101a775aa | ||
|
|
5fda6580e8 | ||
|
|
9185437626 | ||
|
|
bde40c36ae | ||
|
|
894b17e74a | ||
|
|
33b734cbc6 | ||
|
|
3e8454412e | ||
|
|
420f99c5d0 | ||
|
|
98052e4166 | ||
|
|
e971856c74 | ||
|
|
09ee73c31d | ||
|
|
0c4d1365e9 | ||
|
|
b3f941c3f5 | ||
|
|
67e11a9aeb | ||
|
|
7d5f8ca4b4 | ||
|
|
7695acc798 | ||
|
|
3f48a0b803 | ||
|
|
fd731154ff | ||
|
|
906bc94a5f | ||
|
|
db03e7de10 | ||
|
|
97e03fd29f | ||
|
|
09b8bb93a7 | ||
|
|
f9133b1680 | ||
|
|
8aa21bd99a | ||
|
|
e5b6aedd3d | ||
|
|
4b405c69b6 | ||
|
|
9af20c778f | ||
|
|
d1621dca87 | ||
|
|
31b047d29b | ||
|
|
39970c3847 | ||
|
|
e0c65c9d6d | ||
|
|
59d0cd2eeb | ||
|
|
8d11fb8594 | ||
|
|
aec3fa6879 | ||
|
|
ab6602407e | ||
|
|
42ab0c985d | ||
|
|
b215828133 | ||
|
|
e3af4ce6a7 | ||
|
|
96c6edcc37 | ||
|
|
b198ec8633 | ||
|
|
c8a87381e8 | ||
|
|
548e033e7e | ||
|
|
fc097f3446 | ||
|
|
eb92a95134 | ||
|
|
c706461f10 | ||
|
|
b0ad5eb915 | ||
|
|
94f88cc8ba | ||
|
|
1e414afbeb | ||
|
|
869ec42082 | ||
|
|
4893819b4c | ||
|
|
fb1b952769 | ||
|
|
859380285f | ||
|
|
2af55c9bc3 | ||
|
|
4725b1be96 | ||
|
|
5af5f0c55d | ||
|
|
e84f395c97 | ||
|
|
fbf51ad96e | ||
|
|
52433339ec | ||
|
|
f277d5502f | ||
|
|
794122ec13 | ||
|
|
65b266e9b3 | ||
|
|
ca6eddc235 | ||
|
|
8793decd1c | ||
|
|
628aaabd04 | ||
|
|
3544167f26 | ||
|
|
9cca9c989b | ||
|
|
f42c291fef | ||
|
|
dacdd397ab | ||
|
|
c0f02d453a | ||
|
|
627ed5cbd5 | ||
|
|
3fb64f9fe0 | ||
|
|
254958bae9 | ||
|
|
1cb47220f1 | ||
|
|
d9be4f9ce0 | ||
|
|
2cd5aadf9d | ||
|
|
6ebcc6f3a2 | ||
|
|
21ce572dd6 | ||
|
|
1c47a30446 | ||
|
|
5b8ccb60a6 | ||
|
|
89fc74facf | ||
|
|
5a79a5e609 | ||
|
|
c92f9bed42 | ||
|
|
bfb534378b | ||
|
|
0ddcf8b129 | ||
|
|
a66376b8a0 | ||
|
|
9cb53d90fe | ||
|
|
a31cec5e81 | ||
|
|
5367a3528d | ||
|
|
669e7295c6 | ||
|
|
a7f32d1b0f | ||
|
|
efc531a2a9 | ||
|
|
8b959c9ede | ||
|
|
68051f9987 | ||
|
|
3636657ca0 | ||
|
|
f282ef8bbc | ||
|
|
d5fbb21f72 | ||
|
|
57e9bf58a5 | ||
|
|
0ce21d9b45 | ||
|
|
89649fbeb0 | ||
|
|
5924c0f340 | ||
|
|
2f9f10c182 | ||
|
|
d7c98c4819 | ||
|
|
cd0ba369b8 | ||
|
|
bebc84522d | ||
|
|
e7875c78bc | ||
|
|
0a37694436 | ||
|
|
742a11bfdc | ||
|
|
1e7262ce31 | ||
|
|
d733cf6560 | ||
|
|
3818dda9d9 | ||
|
|
18c4a49aa3 | ||
|
|
77f7a362d0 | ||
|
|
738fadc016 | ||
|
|
b97f30f36f | ||
|
|
de05e7a4b8 | ||
|
|
5fe024838b | ||
|
|
8b07fe12e6 | ||
|
|
cd828d6bca | ||
|
|
b60103b839 | ||
|
|
684e9f6791 | ||
|
|
5acc4c8ec3 | ||
|
|
a5c2b9276a | ||
|
|
8d15fceb92 | ||
|
|
913a3eba9e | ||
|
|
041e62bf0b | ||
|
|
e61f571f7c | ||
|
|
36d00b615d | ||
|
|
25d340b5c5 | ||
|
|
8f06c1f90f | ||
|
|
ae6a0745ff | ||
|
|
1d924af9d2 | ||
|
|
fed432877c | ||
|
|
46261091dd | ||
|
|
c356b69a13 | ||
|
|
6cff484b8c | ||
|
|
8314dff386 | ||
|
|
dc40ac1117 | ||
|
|
288b9668b7 | ||
|
|
3c0697b81e | ||
|
|
6e4e46386f | ||
|
|
9b179567da | ||
|
|
b20e17dd13 | ||
|
|
3dcfafc0de | ||
|
|
348bcac0ff | ||
|
|
a43c3b4967 | ||
|
|
40bf991153 | ||
|
|
8f98c01b77 | ||
|
|
18a8cfb88d | ||
|
|
2acdeef320 | ||
|
|
23c09b4b1b | ||
|
|
84c71d6b07 | ||
|
|
c6aa6bccb8 | ||
|
|
041c665185 | ||
|
|
70f9c0305d | ||
|
|
66e41bd862 | ||
|
|
5140d03b4d | ||
|
|
b016179ccc | ||
|
|
efaea581a1 | ||
|
|
24dfaa0ff7 | ||
|
|
f4a72da40e | ||
|
|
6376d07266 | ||
|
|
ea94ee4ca5 | ||
|
|
452605e854 | ||
|
|
dea8f00c01 | ||
|
|
b9d6b27b4e | ||
|
|
300ef0b462 | ||
|
|
6e79272e8d | ||
|
|
d65991d402 | ||
|
|
de94449a87 | ||
|
|
faeb57b35c | ||
|
|
e1332d277c | ||
|
|
e4c2a48696 | ||
|
|
6415367f15 | ||
|
|
fcf2842d87 | ||
|
|
422dccd8da | ||
|
|
abd08a94ea | ||
|
|
e877f7455a | ||
|
|
70c224f429 | ||
|
|
5f7c525023 | ||
|
|
16de5ec22c | ||
|
|
e635bcfea7 | ||
|
|
12b60447da | ||
|
|
5c804d49d0 | ||
|
|
cde19135eb | ||
|
|
77da84c5a8 | ||
|
|
2663762a9a |
No files matched your search
@@ -0,0 +1,14 @@
|
||||
# Pwntools Issue Template
|
||||
|
||||
Thanks for contributing to Pwntools!
|
||||
|
||||
When reporting an issue, be sure that you are running the latest released version of pwntools (`pip install --upgrade pwntools`).
|
||||
|
||||
Please verify that your issue occurs on 64-bit Ubuntu 14.04. You can use the Dockerfile on `docker.io` for quick testing.
|
||||
|
||||
```
|
||||
$ docker pull pwntools/pwntools:stable
|
||||
$ docker run -it pwntools/pwntools:stable
|
||||
```
|
||||
|
||||
If possible, provide a proof-of-concept which demonstrates the problem. Include any binaries or scripts necessary to reproduce the issue, and please include the full debug output via setting the environment variable `PWNLIB_DEBUG=1`.
|
||||
@@ -0,0 +1,27 @@
|
||||
# Pwntools Pull Request
|
||||
|
||||
Thanks for contributing to Pwntools! Take a moment to look at [`CONTRIBUTING.md`][contributing] to make sure you're familiar with Pwntools development.
|
||||
|
||||
Please provide a high-level explanation of what this pull request is for.
|
||||
|
||||
## Testing
|
||||
|
||||
Pull Requests that introduce new code should try to add doctests for that code. See [`TESTING.md`][testing] for more information.
|
||||
|
||||
## Target Branch
|
||||
|
||||
Depending on what the PR is for, it needs to target a different branch.
|
||||
|
||||
You can always [change the branch][change] after you create the PR if it's against the wrong branch.
|
||||
|
||||
| Branch | Type of PR |
|
||||
| -------- | ---------------------------------------------------------------- |
|
||||
| `dev` | New features, and enhancements
|
||||
| `dev` | Documentation fixes and new tests
|
||||
| `stable` | Bug fixes that affect the current `stable` branch
|
||||
| `beta` | Bug fixes that affect the current `beta` branch, but not `stable`
|
||||
| `dev` | Bug fixes for code that has never been released
|
||||
|
||||
[contributing]: https://github.com/Gallopsled/pwntools/blob/dev/CONTRIBUTING.md
|
||||
[testing]: https://github.com/Gallopsled/pwntools/blob/dev/TESTING.md
|
||||
[change]: https://github.com/blog/2224-change-the-base-branch-of-a-pull-request
|
||||
@@ -14,3 +14,4 @@ dist
|
||||
*.egg-info
|
||||
*.core
|
||||
.coverage
|
||||
.tox
|
||||
+24
-10
@@ -1,26 +1,37 @@
|
||||
sudo: false
|
||||
dist: trusty
|
||||
language: python
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
- gcc-4.6-arm-linux-gnueabihf
|
||||
- lib32stdc++6
|
||||
- ash
|
||||
- bash
|
||||
- dash
|
||||
- ksh
|
||||
- mksh
|
||||
- zsh
|
||||
- pandoc
|
||||
- gdb
|
||||
cache:
|
||||
- pip
|
||||
- directories:
|
||||
- usr
|
||||
- /home/travis/virtualenv/python2.7.9/lib/python2.7/site-packages/
|
||||
- /home/travis/virtualenv/python2.7.9/bin/
|
||||
- /home/travis/virtualenv/python2.7.13/lib/python2.7/site-packages/
|
||||
- /home/travis/virtualenv/python2.7.13/bin/
|
||||
sudo: required
|
||||
python:
|
||||
- "2.7"
|
||||
after_success:
|
||||
- coveralls
|
||||
before_install:
|
||||
- source .travis_install.sh
|
||||
- source .travis_ssh_setup.sh
|
||||
- echo $-
|
||||
- source travis/install.sh
|
||||
- source travis/ssh_setup.sh
|
||||
- echo $-
|
||||
install:
|
||||
- pip install -e .
|
||||
- pip install -r docs/requirements.txt
|
||||
- pip install --upgrade pip
|
||||
- pip install --upgrade appdirs # https://github.com/ActiveState/appdirs/issues/89#issuecomment-282326570
|
||||
- pip install --upgrade --editable .
|
||||
- pip install --upgrade --requirement docs/requirements.txt
|
||||
before_script:
|
||||
- PWNLIB_NOTERM=1 python -c 'from pwn import *; print pwnlib.term.term_mode'
|
||||
- PWNLIB_NOTERM=1 python -c 'from pwn import *; print pwnlib.term.term_mode'
|
||||
@@ -28,3 +39,6 @@ before_script:
|
||||
- PWNLIB_NOTERM=1 python -c 'from pwn import *; print pwnlib.term.term_mode'
|
||||
script:
|
||||
- PWNLIB_NOTERM=1 coverage run -m sphinx -b doctest docs/source docs/build/doctest
|
||||
after_success:
|
||||
- coveralls
|
||||
- source travis/update_demo.sh
|
||||
@@ -1,88 +0,0 @@
|
||||
#!/usr/bin/env bash -e
|
||||
local_deb_extract()
|
||||
{
|
||||
wget $1
|
||||
ar vx *.deb
|
||||
tar xvf data.tar.*
|
||||
rm -f *.tar.* *deb*
|
||||
}
|
||||
|
||||
get_binutils()
|
||||
{
|
||||
BINUTILS_PREFIX='https://launchpad.net/~pwntools/+archive/ubuntu/binutils/+files/binutils-'
|
||||
BINUTILS_SUFFIX='-linux-gnu_2.22-6ubuntu1.1cross0.11pwntools12~precise_amd64.deb'
|
||||
local_deb_extract "${BINUTILS_PREFIX}${1}${BINUTILS_SUFFIX}"
|
||||
}
|
||||
|
||||
get_qemu()
|
||||
{
|
||||
echo "Installing qemu"
|
||||
QEMU_URL='https://mirrors.kernel.org/ubuntu/pool/universe/q/qemu/qemu-user-static_2.6%2bdfsg-3ubuntu1_amd64.deb'
|
||||
local_deb_extract "$QEMU_URL"
|
||||
}
|
||||
|
||||
setup_travis()
|
||||
{
|
||||
export PATH=$PWD/usr/bin:$PATH
|
||||
export LD_LIBRARY_PATH=$PWD/usr/lib
|
||||
|
||||
if [ ! -d usr/bin ];
|
||||
then
|
||||
# Install our custom binutils
|
||||
which arm-linux-as || get_binutils arm
|
||||
which mips-linux-as || get_binutils mips
|
||||
which powerpc-linux-as || get_binutils powerpc
|
||||
which aarch64-linux-as || get_binutils aarch64
|
||||
|
||||
# Install the multiarch binutils
|
||||
local_deb_extract http://mirrors.mit.edu/ubuntu/ubuntu/pool/universe/b/binutils/binutils-multiarch_2.22-6ubuntu1_amd64.deb
|
||||
fi
|
||||
|
||||
if ! (which qemu-arm-static && qemu-arm-static -version | grep 2.6.0); then
|
||||
get_qemu
|
||||
fi
|
||||
|
||||
# Get rid of files we don't want cached
|
||||
rm -rf usr/share
|
||||
|
||||
pushd usr/lib
|
||||
ln -sf libbfd-2.22-multiarch.so libbfd-2.22.so
|
||||
ln -sf libopcodes-2.22-multiarch.so libopcodes-2.22.so
|
||||
popd
|
||||
|
||||
which arm-linux-gnu-as
|
||||
which mips-linux-gnu-as
|
||||
which powerpc-linux-gnu-as
|
||||
which aarch64-linux-gnu-as
|
||||
which qemu-arm-static
|
||||
}
|
||||
|
||||
setup_linux()
|
||||
{
|
||||
sudo apt-get install -y software-properties-common openssh-server libncurses5-dev libncursesw5-dev
|
||||
sudo apt-add-repository --yes ppa:pwntools/binutils
|
||||
sudo apt-get update
|
||||
sudo apt-get install binutils-arm-linux-gnu binutils-mips-linux-gnu binutils-powerpc-linux-gnu
|
||||
}
|
||||
|
||||
setup_osx()
|
||||
{
|
||||
brew update
|
||||
brew install binutils
|
||||
brew install capstone
|
||||
}
|
||||
|
||||
if [[ "$USER" == "travis" ]]; then
|
||||
setup_travis
|
||||
elif [[ "$USER" == "shippable" ]]; then
|
||||
sudo apt-get update
|
||||
sudo apt-get install openssh-server gcc-multilib
|
||||
sudo /usr/sbin/sshd -f /etc/ssh/sshd_config &
|
||||
setup_travis
|
||||
elif [[ "$(uname)" == "Darwin" ]]; then
|
||||
setup_osx
|
||||
elif [[ "$(uname)" == "Linux" ]]; then
|
||||
setup_linux
|
||||
fi
|
||||
|
||||
dpkg -l
|
||||
@@ -1,54 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Install a demo user for SSH purposes
|
||||
#
|
||||
# All of the "conditional sudo" is to do container-based builds on
|
||||
# Travis which are much, much faster.
|
||||
U=travis
|
||||
H=/home/$U
|
||||
|
||||
USUDO()
|
||||
{
|
||||
if [[ "$USER" == "travis" ]];
|
||||
then
|
||||
$*
|
||||
else
|
||||
sudo -u $U $*
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
if [[ "$USER" == "travis" ]];
|
||||
then
|
||||
rm -f ~/.ssh/*
|
||||
else
|
||||
# Create the new user account
|
||||
# Disable password login for the user, and ensure the account is not locked
|
||||
sudo useradd -m $U
|
||||
sudo passwd --delete --unlock $U
|
||||
fi
|
||||
|
||||
# Generate a new key so that we can log into it
|
||||
ssh-keygen -t rsa -f ~/.ssh/$U -N ''
|
||||
|
||||
# Load the public key into a memory for below
|
||||
pubkey=$(cat ~/.ssh/$U.pub)
|
||||
|
||||
# Set the authorized_keys entry to only permit login from localhost,
|
||||
# and only with
|
||||
USUDO mkdir $H/.ssh
|
||||
USUDO tee -a $H/.ssh/authorized_keys <<EOF
|
||||
from="127.0.0.1" $pubkey
|
||||
EOF
|
||||
|
||||
# In the pwntools examples, we ssh to 'example.pwnme'
|
||||
# Set up an SSH config entry to make this actually work
|
||||
cat >> ~/.ssh/config <<EOF
|
||||
|
||||
Host example.pwnme
|
||||
User $U
|
||||
HostName 127.0.0.1
|
||||
IdentityFile ~/.ssh/$U
|
||||
EOF
|
||||
|
||||
ssh -o "StrictHostKeyChecking no" -vvvv [email protected] id
|
||||
+492
-4
@@ -3,7 +3,495 @@
|
||||
This changelog only includes added major features and changes. Bugfixes and
|
||||
minor changes are omitted.
|
||||
|
||||
## 3.0.0 (August 20 2016)
|
||||
## Release History
|
||||
|
||||
The table below shows which release corresponds to each branch, and what date the version was released.
|
||||
|
||||
| Version | Branch | Release Date |
|
||||
| ---------------- | -------- | ---------------------- |
|
||||
| [3.14.0](#3130) | `dev` | Jun 12, 2018 (planned)
|
||||
| [3.13.0](#3130) | `beta` | Mar 31, 2018 (planned)
|
||||
| [3.12.0](#3120) | `stable` | Feb 22, 2018
|
||||
| [3.11.0](#3110) | | Jan 3, 2018
|
||||
| [3.10.0](#3100) | | Oct 25, 2017
|
||||
| [3.9.2](#392) | | Oct 5, 2017
|
||||
| [3.9.1](#391) | | Sep 28, 2017
|
||||
| [3.9.0](#390) | | Sep 11, 2017
|
||||
| [3.8.0](#380) | | Jul 29, 2017
|
||||
| [3.7.1](#371) | | Jul 14, 2017
|
||||
| [3.7.0](#370) | | Jun 19, 2017
|
||||
| [3.6.1](#361) | | May 12, 2017
|
||||
| [3.6.0](#360) | | May 8, 2017
|
||||
| [3.5.1](#351) | | Apr 15, 2017
|
||||
| [3.5.0](#350) | | Mar 26, 2017
|
||||
| [3.4.1](#341) | | Feb 17, 2017
|
||||
| [3.4.0](#340) | | Feb 13, 2017
|
||||
| [3.3.4](#334) | | Jan 12, 2016
|
||||
| [3.3.3](#333) | | Jan 10, 2016
|
||||
| [3.3.2](#332) | | Jan 10, 2016
|
||||
| [3.3.1](#331) | | Jan 10, 2016
|
||||
| [3.3.0](#330) | | Dec 24, 2016
|
||||
| [3.2.1](#321) | | Dec 24, 2016
|
||||
| [3.2.0](#320) | | Nov 12, 2016
|
||||
| [3.1.1](#311) | | Oct 23, 2016
|
||||
| [3.1.0](#310) | | Oct 2, 2016
|
||||
| [3.0.4](#304) | | Sept 19, 2016
|
||||
| [3.0.3](#303) | | Sept 18, 2016
|
||||
| [3.0.2](#302) | | Sept 6, 2016
|
||||
| [3.0.1](#301) | | Aug 20, 2016
|
||||
| [3.0.0](#300) | | Aug 20, 2016
|
||||
| [2.2.0](#220) | | Jan 5, 2015
|
||||
|
||||
## 3.14.0
|
||||
|
||||
To be released on Jun 12, 2018.
|
||||
|
||||
## 3.13.0
|
||||
|
||||
To be released on Mar 31, 2018.
|
||||
|
||||
- [#1104][1104] Add `DynELF.dump()` for dumping remote ELF files
|
||||
- [#1101][1101] Set `context.os` via `context.binary`, useful for Android exploitation
|
||||
- [5fdc08][5fdc08] Work around broken `pidof` on Android
|
||||
- [63dfed][63dfed] Print warning when Corefile deletion fails instead of throwing an exception
|
||||
- [#1094][1094] Make hexdump output alignment more consistent
|
||||
- [#1096][1096] `flat()` and `fit()` are now the same function
|
||||
- [#1068][1068] Work around very old OpenSSL versions which don't have sha256 support *AND* don't exit with an error code when trying to use it
|
||||
|
||||
[1104]: https://github.com/Gallopsled/pwntools/pull/1104
|
||||
[1101]: https://github.com/Gallopsled/pwntools/pull/1101
|
||||
[1094]: https://github.com/Gallopsled/pwntools/pull/1094
|
||||
[1096]: https://github.com/Gallopsled/pwntools/pull/1096
|
||||
[1068]: https://github.com/Gallopsled/pwntools/pull/1068
|
||||
[5fdc08]: https://github.com/Gallopsled/pwntools/commit/5fdc08
|
||||
[63dfed]: https://github.com/Gallopsled/pwntools/commit/63dfed
|
||||
|
||||
## 3.12.0
|
||||
|
||||
- [#1083][1083] Better error messages for `gdb` when `LD_PRELOAD` is incorrect
|
||||
- [#1085][1085] Add support for extracting Android `BOOTLDR!` images
|
||||
- [#1075][1075] Add support for detecting GNU Screen for `run_in_new_terminal`
|
||||
- [#1074][1074] Add support for running `pwntools-gdb` wrapper script instead of `gdb`
|
||||
- [#1067][1067] Add `pwnlib.tubes.server` module, which adds a reusable `server` listener
|
||||
- [#1063][1063] Add support for labels in `fit()`, allowing dynamic contents to be injected. (This feature is really cool, check out the pull request!)
|
||||
|
||||
[1083]: https://github.com/Gallopsled/pwntools/pull/1083
|
||||
[1085]: https://github.com/Gallopsled/pwntools/pull/1085
|
||||
[1075]: https://github.com/Gallopsled/pwntools/pull/1075
|
||||
[1074]: https://github.com/Gallopsled/pwntools/pull/1074
|
||||
[1067]: https://github.com/Gallopsled/pwntools/pull/1067
|
||||
[1063]: https://github.com/Gallopsled/pwntools/pull/1063
|
||||
|
||||
## 3.11.0
|
||||
|
||||
- [#1044][1044] Enhancements to ROP
|
||||
+ Much better support for 64-bit Intel (amd64) ROP
|
||||
+ ROP gadget selection is optimized to favor multi-pops instead of multiple single-pop gadgets
|
||||
+ Added support for blacklisting byte values in ROP gadget addresses
|
||||
- [#1049][1049] Enhancements to `cyclic`
|
||||
+ `context` now has two additional attributes, `cyclic_alphabet` and `cyclic_length`, which correspond to the arguments `alphabet` and `n` to `cyclic()` and `cyclic_find()` and related routines.
|
||||
+ The motivation for this change is to allow setting the `alphabet` globally, so that any padding / patterns generated internally to pwntools can be controlled. The specific motivation is blacklisting values in ROP padding.
|
||||
- [#1052][1052] Enhancements for detecting `QEMU_LD_PREFIX` used by QEMU user-mode emulation for sysroots
|
||||
- [#1035][1035] Minor documentation changes
|
||||
- [#1032][1032] Enhancements to `pwn template`
|
||||
- [#1031][1031] More accurate `Coredump.fault_addr` on amd64
|
||||
- [#1084][1084] Fix broken tests due to `ftp.debian.org` going down
|
||||
|
||||
[1044]: https://github.com/Gallopsled/pwntools/pull/1044
|
||||
[1049]: https://github.com/Gallopsled/pwntools/pull/1049
|
||||
[1052]: https://github.com/Gallopsled/pwntools/pull/1052
|
||||
[1035]: https://github.com/Gallopsled/pwntools/pull/1035
|
||||
[1032]: https://github.com/Gallopsled/pwntools/pull/1032
|
||||
[1031]: https://github.com/Gallopsled/pwntools/pull/1031
|
||||
[1084]: https://github.com/Gallopsled/pwntools/pull/1084
|
||||
|
||||
## 3.10.0
|
||||
|
||||
- [#1007][1007] Add support for setting a `gdbinit` file in the context
|
||||
- [#1055][1055] Fixes for `Corefile` stack parsing, speed up `ELF.string()`
|
||||
- [#1057][1057] Fix a variable name typo in `DynELF` logging which results in an exception being thrown
|
||||
- [#1058][1058] Fix an edge case in `ssh_process.exe`
|
||||
|
||||
[1007]: https://github.com/Gallopsled/pwntools/pull/1007
|
||||
[1055]: https://github.com/Gallopsled/pwntools/pull/1055
|
||||
[1057]: https://github.com/Gallopsled/pwntools/pull/1057
|
||||
[1058]: https://github.com/Gallopsled/pwntools/pull/1058
|
||||
|
||||
## 3.9.2
|
||||
|
||||
- [#1043][1043] Do not attempt to populate the libraries used by statically-linked binaries
|
||||
|
||||
[1043]: https://github.com/Gallopsled/pwntools/pull/1043
|
||||
|
||||
## 3.9.1
|
||||
|
||||
- [#1038][1038] Fix an issue with `process()` where glibc would buffer data internally, causing a hang on `select()`
|
||||
- [#1036][1036] Fix Travis CI logging verbosity
|
||||
- [#1029][1029] Fix some `unicode` issues when using the `readline` command history in `tube.interactive()`
|
||||
|
||||
[1038]: https://github.com/Gallopsled/pwntools/pull/1038
|
||||
[1036]: https://github.com/Gallopsled/pwntools/pull/1036
|
||||
[1029]: https://github.com/Gallopsled/pwntools/pull/1029
|
||||
|
||||
## 3.9.0
|
||||
|
||||
- [#1003][1003] Make `concat_all` faster while also simplifying it's logic
|
||||
- [#1014][1014] Fix for overwritten env when parsing core file
|
||||
- [#1023][1023] Fixes to Travis CI
|
||||
|
||||
[1003]: https://github.com/Gallopsled/pwntools/pull/1003
|
||||
[1014]: https://github.com/Gallopsled/pwntools/pull/1014
|
||||
[1023]: https://github.com/Gallopsled/pwntools/pull/1023
|
||||
|
||||
## 3.8.0
|
||||
|
||||
- [#981][981] Fixed RELRO detection logic
|
||||
- [#986][986] Enhancements to DynELF for controlling usage of LibcDB
|
||||
- A few documentation fixes
|
||||
- A few fixes for the Docker image
|
||||
|
||||
[981]: https://github.com/Gallopsled/pwntools/pull/981
|
||||
[986]: https://github.com/Gallopsled/pwntools/pull/986
|
||||
|
||||
## 3.7.1
|
||||
|
||||
- [#998][998] Fix a bug where integer values could not be set in `.pwn.conf`.
|
||||
|
||||
[998]: https://github.com/Gallopsled/pwntools/pull/998
|
||||
|
||||
## 3.7.0
|
||||
|
||||
- [#933][933] DynELF works better with different base addresses
|
||||
- [#952][952] A few small fixes were made to `pwn template`, and the CRC database was updated.
|
||||
- [5c72d62c][5c72d62c] Updated the CRC database
|
||||
|
||||
[933]: https://github.com/Gallopsled/pwntools/pull/933
|
||||
[952]: https://github.com/Gallopsled/pwntools/pull/952
|
||||
[5c72d62c]: https://github.com/Gallopsled/pwntools/commit/5c72d62c
|
||||
|
||||
## 3.6.1
|
||||
|
||||
- [#979][979]+[1a4a1e1][1a4a1e1] Fixed [#974][974], a bug related to the terminal handling and numlock.
|
||||
- [#980][980] Fixed the `pwn template` command.
|
||||
|
||||
[974]: https://github.com/Gallopsled/pwntools/issues/974
|
||||
[979]: https://github.com/Gallopsled/pwntools/pull/979
|
||||
[980]: https://github.com/Gallopsled/pwntools/pull/980
|
||||
[1a4a1e1]: https://github.com/Gallopsled/pwntools/commit/1a4a1e1
|
||||
|
||||
## 3.6.0
|
||||
|
||||
- [#895][895] Added a Dockerfile to simplify testing setup and allow testing on OSX
|
||||
- [#897][897] Fixed some incorrect AArch64 syscals
|
||||
- [#893][893] Added the `pwnlib.config` module
|
||||
+ Configuration options can now be set in `~/.pwn.conf`
|
||||
+ This replaces the old, **undocumented** mechanism for changing logging colors. Only @br0ns and @ebeip90 were likely using this.
|
||||
+ More information is available in the documentation [here](http://docs.pwntools.com/en/dev/config.html).
|
||||
- [#899][899] Pwntools now uses Unicorn Engine to emulate PLT instructions to ensure correct mapping of PIE / RELRO binaries.
|
||||
- [#904][904] Enhancements to the accuracy of the `pwn checksec` command.
|
||||
- [#905][905] Added a `pwn debug` command-line utility which automates the process of `gdb.attach(process(...))` to spawn GDB
|
||||
+ More information is available in the documentation [here](http://docs.pwntools.com/en/dev/commandline.html#pwn-debug)
|
||||
- [#919][919] Added a `pwn template` command-line utility to simplify the process of bootstrapping a new exploit.
|
||||
+ More information is available in the documentation [here](http://docs.pwntools.com/en/dev/commandline.html#pwn-template).
|
||||
- [#948][948] Fix unnecessary warning for Core files
|
||||
- [#954][954] Fix list processing in `~/.pwn.conf`
|
||||
- [#967][967] Respect `TERM_PROGRAM` for `run_in_new_terminal`
|
||||
- [#970][970] Fix overly-aggressive corefile caching
|
||||
|
||||
[947]: https://github.com/Gallopsled/pwntools/pull/947
|
||||
[948]: https://github.com/Gallopsled/pwntools/pull/948
|
||||
[954]: https://github.com/Gallopsled/pwntools/pull/954
|
||||
[960]: https://github.com/Gallopsled/pwntools/pull/960
|
||||
[967]: https://github.com/Gallopsled/pwntools/pull/967
|
||||
[968]: https://github.com/Gallopsled/pwntools/pull/968
|
||||
[970]: https://github.com/Gallopsled/pwntools/pull/970
|
||||
|
||||
[895]: https://github.com/Gallopsled/pwntools/pull/895
|
||||
[897]: https://github.com/Gallopsled/pwntools/pull/897
|
||||
[893]: https://github.com/Gallopsled/pwntools/pull/893
|
||||
[899]: https://github.com/Gallopsled/pwntools/pull/899
|
||||
[904]: https://github.com/Gallopsled/pwntools/pull/904
|
||||
[905]: https://github.com/Gallopsled/pwntools/pull/905
|
||||
[919]: https://github.com/Gallopsled/pwntools/pull/919
|
||||
|
||||
## 3.5.1
|
||||
|
||||
- [#945][945] Speed up ssh via caching checksec results (fixes [#944][944])
|
||||
- [#950][950] Fixes a bug where setting `context.arch` does not have an effect on `adb.compile()` output architecture
|
||||
|
||||
[944]: https://github.com/Gallopsled/pwntools/issues/944
|
||||
[945]: https://github.com/Gallopsled/pwntools/pull/945
|
||||
[950]: https://github.com/Gallopsled/pwntools/pull/950
|
||||
|
||||
## 3.5.0
|
||||
|
||||
- [b584ca3][b584ca3] Fixed an issue running `setup.py` on ARM
|
||||
- [#822][822] Enabled relative leaks with `MemLeak`
|
||||
+ This should be useful for e.g. heap-relative leaks
|
||||
- [#832][832] Changed all internal imports to use absolute imports (no functional changes)
|
||||
- [a12d0b6][a12d0b6] Move `STDOUT`, `PIPE`, `PTY` constants to globals
|
||||
+ `process(..., stdin=process.PTY)` --> `process(..., stdin=PTY)`
|
||||
- [#828][828] Use `PR_SET_PTRACER` for all `process()` and `ssh.process()` instances
|
||||
+ This simplifies debugging on systems with YAMA ptrace enabled
|
||||
- Various documentation enhancements
|
||||
+ In particular, the [gdb][gdb], [elf][elf], and [ssh][ssh] docs are much better
|
||||
- [#833][833] Performance enhancements for `adb` module
|
||||
- [d0267f3][d0267f3] `packing.fit()` now treats large offsets as cyclic patterns (e.g. `0x61616161` behaves the same as `"aaaa"`)
|
||||
- [#835][835] Added `ssh.checksec`
|
||||
+ Reports the kernel version and other relevant information on connection
|
||||
- [#857][857] Slightly shortened `execve` shellcode
|
||||
- [300f8e0][300f8e0] Slightly speed up processing of large ELF files
|
||||
- [#861][861] Adds support for extracting `IKCONFIG` configs from Linux kernel images, and extends `checksec` to report on any insecure configurations discovered
|
||||
- [#871][871] Moves all of the basic syscall templates to `shellcraft/common` and exposes them via symlinks. Closed [#685][685]
|
||||
+ Should not have any visible effects from any documented APIs
|
||||
+ `shellcraft.arch.os.syscall_function()` still works the same
|
||||
+ We now have the ability to differentiate between the `connect` syscall, and a TCP `connect` helper
|
||||
- [#887][887] `sh_string` now returns a quoted empty string `''` rather than just an empty string
|
||||
- [#839][839] Exposes a huge amount of functionality via corefiles which was not previously availble. See the [docs][corefile_docs] for examples.
|
||||
+ `process().corefile` will automatically instantiate a Corefile for the process
|
||||
+ QEMU-emulated processes are supported
|
||||
+ Native processes are supported, including extraction of coredumps from `apport` crash logs
|
||||
+ Native processes can be dumped *while running*, in a manner similar to `GDB`'s `gcore` script
|
||||
- [#875][857] Added [documentation][aarch64] (and tests) for AArch64 shellcode
|
||||
- [#882][882] The `ROP` class now respects `context.bytes` instead of using the hard-coded value of `4` (fixed [#879][879])
|
||||
- [#869][869] Added several fields to the `process` class (`uid`, `gid`, `suid`, `sgid`) which are recorded at execution time, based on the file permissions
|
||||
- [#868][868] Changed the way that `ssh.process()` works internally, and it now returns a more specialized class, `ssh_process`.
|
||||
+ Added `ssh_process.corefile` for fetching remote corefiles
|
||||
+ Added `ssh_process.ELF` for getting an ELF of the remote executable
|
||||
+ The `uid`, `gid`, and `suid`, and `sgid` which are recorded at execution time, based on the file permissions
|
||||
- [#865][865] Fixes `ELF.read` to support contiguous memory reads across non-contiguous file-backed segments
|
||||
- [#862][862] Adds a `symlink=` argument to `ssh.set_working_directory`, which will automatically symlink all of the files in the "old" working directory into the "new" working directory
|
||||
|
||||
[ssh]: http://docs.pwntools.com/en/dev/tubes/ssh.html
|
||||
[gdb]: http://docs.pwntools.com/en/dev/gdb.html
|
||||
[elf]: http://docs.pwntools.com/en/dev/elf.html
|
||||
[corefile_docs]: http://docs.pwntools.com/en/dev/elf/corefile.html
|
||||
[aarch64]: http://docs.pwntools.com/en/dev/shellcraft/aarch64.html
|
||||
|
||||
[685]: https://github.com/Gallopsled/pwntools/pull/685
|
||||
[822]: https://github.com/Gallopsled/pwntools/pull/822
|
||||
[828]: https://github.com/Gallopsled/pwntools/pull/828
|
||||
[832]: https://github.com/Gallopsled/pwntools/pull/832
|
||||
[833]: https://github.com/Gallopsled/pwntools/pull/833
|
||||
[835]: https://github.com/Gallopsled/pwntools/pull/835
|
||||
[839]: https://github.com/Gallopsled/pwntools/pull/839
|
||||
[857]: https://github.com/Gallopsled/pwntools/pull/857
|
||||
[861]: https://github.com/Gallopsled/pwntools/pull/861
|
||||
[862]: https://github.com/Gallopsled/pwntools/pull/862
|
||||
[865]: https://github.com/Gallopsled/pwntools/pull/865
|
||||
[868]: https://github.com/Gallopsled/pwntools/pull/868
|
||||
[869]: https://github.com/Gallopsled/pwntools/pull/869
|
||||
[871]: https://github.com/Gallopsled/pwntools/pull/871
|
||||
[875]: https://github.com/Gallopsled/pwntools/pull/857
|
||||
[879]: https://github.com/Gallopsled/pwntools/issues/879
|
||||
[882]: https://github.com/Gallopsled/pwntools/pull/882
|
||||
[887]: https://github.com/Gallopsled/pwntools/pull/887
|
||||
|
||||
|
||||
[b584ca3]: https://github.com/Gallopsled/pwntools/commit/b584ca3
|
||||
[a12d0b6]: https://github.com/Gallopsled/pwntools/commit/a12d0b6
|
||||
[d0267f3]: https://github.com/Gallopsled/pwntools/commit/d0267f3
|
||||
[300f8e0]: https://github.com/Gallopsled/pwntools/commit/300f8e0
|
||||
|
||||
## 3.4.1
|
||||
|
||||
- [#894][894] Fix a bug when using `gdb.debug()` over ssh.
|
||||
- [e021f57][e021f57] Fix a bug ([#891][891]) in `rop` when needing to insert padding to fix alignment
|
||||
|
||||
[e021f57]: https://github.com/Gallopsled/pwntools/commit/e021f57
|
||||
[894]: https://github.com/Gallopsled/pwntools/pull/894
|
||||
[891]: https://github.com/Gallopsled/pwntools/issues/891
|
||||
|
||||
## 3.4.0
|
||||
|
||||
- [#800][800] Add `shell=` option to `ssh.process()`
|
||||
- [#806][806] Add `context.buffer_size` for fine-tuning `tube` performance
|
||||
+ Also adds `buffer_fill_size=` argument for all tubes
|
||||
- [b83a6c7][b83a6c7] Fix undocumented `process.leak` function
|
||||
- [546061e][546061e] Modify `coredump_filter` of all spawned processes, so that core dumps are more complete
|
||||
- [#809][809] Add several functions to `adb` (`unlink`, `mkdir`, `makedirs`, `isdir`, `exists`)
|
||||
- [#817][817] Make disconnection detection more robust
|
||||
|
||||
[800]: https://github.com/Gallopsled/pwntools/pull/800
|
||||
[806]: https://github.com/Gallopsled/pwntools/pull/806
|
||||
[809]: https://github.com/Gallopsled/pwntools/pull/809
|
||||
[817]: https://github.com/Gallopsled/pwntools/pull/817
|
||||
[5d9792f]: https://github.com/Gallopsled/pwntools/commit/5d9792f
|
||||
[b83a6c7]: https://github.com/Gallopsled/pwntools/commit/b83a6c7
|
||||
[546061e]: https://github.com/Gallopsled/pwntools/commit/546061e
|
||||
|
||||
## 3.3.4
|
||||
|
||||
- [#850][850] and [#846][846] fix issues with `hexdump` and the `phd` command-line utility, when using pipes (e.g. `echo foo | phd`)
|
||||
- [#852][852] Fixes register ordering in `regsort`
|
||||
- [#853][853] Fixes the registers restored in `shellcraft.amd64.popad`
|
||||
|
||||
[846]: https://github.com/gallopsled/pwntools/pull/846
|
||||
[850]: https://github.com/gallopsled/pwntools/pull/850
|
||||
[852]: https://github.com/gallopsled/pwntools/pull/852
|
||||
[853]: https://github.com/gallopsled/pwntools/pull/853
|
||||
|
||||
## 3.3.3
|
||||
|
||||
- [#843][843] fixed a bug in `amd64.mov`.
|
||||
|
||||
[843]: https://github.com/gallopsled/pwntools/pull/843
|
||||
|
||||
## 3.3.2
|
||||
|
||||
- [#840][840] fixed a regression introduced by [#837][837].
|
||||
|
||||
[840]: https://github.com/gallopsled/pwntools/pull/840
|
||||
|
||||
## 3.3.1
|
||||
|
||||
- [#833][833] Fixed a performance-impacting bug in the adb module.
|
||||
- [#837][837] Fixed a bug([#836][836]) causing `hexdump(cyclic=True)` to throw an exception.
|
||||
|
||||
[833]: https://github.com/Gallopsled/pwntools/pull/833
|
||||
[837]: https://github.com/Gallopsled/pwntools/pull/837
|
||||
[836]: https://github.com/Gallopsled/pwntools/issues/836
|
||||
|
||||
## 3.3.0
|
||||
|
||||
- [b198ec8][b198ec8] Added `tube.stream()` function, which is like `tube.interact()` without a prompt or keyboard input.
|
||||
+ Effectively, this is similar to `cat file` and just prints data as fast as it is received.
|
||||
- [aec3fa6][aec3fa6] Disable update checks against GitHub
|
||||
+ These checks frequently broke due to GitHub query limits
|
||||
- [#757][757] Fixed `adb.wait_for_device()` re-use of the same connection
|
||||
- [f9133b1][f9133b1] Add a `STDERR` magic argument to make logging go to `stderr` instead of `stdout`
|
||||
+ Usage is e.g. `python foo.py STDERR` or `PWNLIB_STDERR=1 python foo.py`
|
||||
+ Also adds `context.log_console` to log to any file or terminal
|
||||
- [67e11a9][67e11a9] Add faster error checking to `cyclic()` when provided very large values
|
||||
- [5fda658][5fda658] Expose BitPolynom in `globals()`
|
||||
- [#765][765] Added `-d` option for hex-escaped output for `shellcraft` command-line tool
|
||||
- [#772][772] Fixed bash completion regressions
|
||||
- [30c34b7][30c34b7] Fix `ROP.call()` with `Function` objects from `ELF.functions`
|
||||
- [fa402ce][fa402ce] Add `adb.uptime` and `adb.boot_time`
|
||||
- [82312ba][82312ba] Add `cyclic_metasploit` and `cyclic_metasploit_find`
|
||||
|
||||
[757]: https://github.com/Gallopsled/pwntools/pull/757
|
||||
[765]: https://github.com/Gallopsled/pwntools/pull/765
|
||||
[772]: https://github.com/Gallopsled/pwntools/pull/772
|
||||
[b198ec8]: https://github.com/Gallopsled/pwntools/commit/b198ec8
|
||||
[aec3fa6]: https://github.com/Gallopsled/pwntools/commit/aec3fa6
|
||||
[f9133b1]: https://github.com/Gallopsled/pwntools/commit/f9133b1
|
||||
[67e11a9]: https://github.com/Gallopsled/pwntools/commit/67e11a9
|
||||
[5fda658]: https://github.com/Gallopsled/pwntools/commit/5fda658
|
||||
[30c34b7]: https://github.com/Gallopsled/pwntools/commit/30c34b7
|
||||
[fa402ce]: https://github.com/Gallopsled/pwntools/commit/fa402ce
|
||||
[82312ba]: https://github.com/Gallopsled/pwntools/commit/82312ba
|
||||
|
||||
## 3.2.1
|
||||
|
||||
Multiple bug fixes.
|
||||
|
||||
- [#783][783] Fix `adb.uninstall` typo
|
||||
- [#787][787] Added error handling for `ssh.process` argument `preexec_fn`
|
||||
- [#793][793] Fixed progress message in `remote()` when connections failed
|
||||
- [#802][802] Fixed partition listing in `adb.partitions`, which accidentally shelled out to the `adb` binary
|
||||
- [#804][804] Fix error message for 32-bit distributions
|
||||
- [#805][805] Fix exception in `Core.segments` when a segment has no name
|
||||
- [#811][811] Fixes and performance improvements for `adb.wait_for_device()`
|
||||
- [#813][813] Fixed a release script
|
||||
- [#814][814] Fixed exceptions thrown if the `$HOME` directory is not writable
|
||||
- [#815][815] Properly handle `None` in `MemLeak`
|
||||
|
||||
[783]: https://github.com/Gallopsled/pwntools/pull/783
|
||||
[787]: https://github.com/Gallopsled/pwntools/pull/787
|
||||
[793]: https://github.com/Gallopsled/pwntools/pull/793
|
||||
[802]: https://github.com/Gallopsled/pwntools/pull/802
|
||||
[804]: https://github.com/Gallopsled/pwntools/pull/804
|
||||
[805]: https://github.com/Gallopsled/pwntools/pull/805
|
||||
[811]: https://github.com/Gallopsled/pwntools/pull/811
|
||||
[813]: https://github.com/Gallopsled/pwntools/pull/813
|
||||
[814]: https://github.com/Gallopsled/pwntools/pull/814
|
||||
[815]: https://github.com/Gallopsled/pwntools/pull/815
|
||||
|
||||
## 3.2.0
|
||||
|
||||
- [#695][695] Fixed a performance regression in `phd`.
|
||||
- [452605e][452605e] Fixed [#629][629] related to correct removal of temporary files.
|
||||
- [ea94ee4][ea94ee4] Disallows semi-colons in for the `run_in_terminal` function, since it did not work properly in all cases.
|
||||
- [6376d07][6376d07] Added the mips shellcode `pushstr_array`.
|
||||
- [#700][700] Added missing MIPS shellcode documentation to readthedocs, and enabled unit tests
|
||||
- [#701][701] Command line tools refactored to have a common `pwn` entry point.
|
||||
+ Added an option to *not* install the traditional `asm`, `disasm`, `checksec`, etc scripts
|
||||
+ All existing tools can be accessed from the `pwn` command (e.g. `pwn asm nop`).
|
||||
- [#704][704] The `process` object has a new, optional argument `alarm` for setting a `SIGALRM` timeout for processes.
|
||||
- [#705][705] Added the Android Emulator to the test suite and Travis CI.
|
||||
+ Android Emulator is now required for the full test suite
|
||||
+ Android Emulator tests are skipped if no Android-related changes are detected
|
||||
- [#711][711] `DynELF` has a new attribute, `heap`, which leaks the current `brk` address (heap base). This is useful for finding heap allocations with dlmalloc-derived allocators like those used by Glibc.
|
||||
- [#717][717] `sh_string` was rewritten to emit more compact and compatible strings
|
||||
+ This was achieved by embedding single-quoted non-printable literals
|
||||
+ Much more testing was added
|
||||
+ Emitted strings are no longer copy-paste compatible, but work fine with e.g. `tubes` module and the default `subprocess` module
|
||||
- [#709][709] The `adb` module now directly talks to the `adb` server process via a new module, `adb.protocol`
|
||||
+ Removes the need to shell out to `adb`
|
||||
+ Avoids version-compatibility issues with `adb` server vs. client
|
||||
- [#703][703] Added new methods to `adb`
|
||||
+ `install` - Installs an APK
|
||||
+ `uninstall` - Uninstalls a package
|
||||
+ `packages` - Lists installed packages
|
||||
- [4893819][4893819] Modified `shellcraft.sh` on all platforms to provide `argv[0]` and set `argc==1`
|
||||
+ This is needed for systems which have Busybox or other minimal shell for `/bin/sh` which does not behave well with `argc==0` or `argv[0]==NULL`.
|
||||
- [1e414af][1e414af] Added `connect()` alias for `remote()`
|
||||
+ For example, `io=connect('google.com', 80)`
|
||||
+ This also works with `tcp(...)` and `udp(...)` aliases
|
||||
- [869ec42][869ec42] Added `ssh.read()` and `ssh.write()` aliases
|
||||
- [2af55c9][2af55c9] `AdbDevice` objects exposed via e.g. `adb.devices()` now offer scoped access to all `adb` module properties
|
||||
+ It is now possible to e.g. `map(lambda d: d.process(['id']).recvall(), adb.devices())`
|
||||
|
||||
|
||||
[629]: https://github.com/Gallopsled/pwntools/issues/629
|
||||
[695]: https://github.com/Gallopsled/pwntools/pull/695
|
||||
[700]: https://github.com/Gallopsled/pwntools/pull/700
|
||||
[701]: https://github.com/Gallopsled/pwntools/pull/701
|
||||
[704]: https://github.com/Gallopsled/pwntools/pull/704
|
||||
[711]: https://github.com/Gallopsled/pwntools/pull/711
|
||||
[717]: https://github.com/Gallopsled/pwntools/pull/717
|
||||
[709]: https://github.com/Gallopsled/pwntools/pull/709
|
||||
[705]: https://github.com/Gallopsled/pwntools/pull/705
|
||||
[703]: https://github.com/Gallopsled/pwntools/pull/703
|
||||
[452605e]: https://github.com/Gallopsled/pwntools/commit/452605e854f4870ef5ccfdf7fb110dfd75c50feb
|
||||
[ea94ee4]: https://github.com/Gallopsled/pwntools/commit/ea94ee4ca5a8060567cc9bd0dc33796a89ad0b95
|
||||
[6376d07]: https://github.com/Gallopsled/pwntools/commit/6376d072660fb2250f48bd22629bbd7e3c61c758
|
||||
[1e414af]: https://github.com/Gallopsled/pwntools/commit/1e414afbeb3a01242f4918f111febaa63b640eb7
|
||||
[869ec42]: https://github.com/Gallopsled/pwntools/commit/869ec42082b4b98958dfe85103da9b101dde7daa
|
||||
[4893819]: https://github.com/Gallopsled/pwntools/commit/4893819b4c23182da570e2f4ea4c14d73af2c0df
|
||||
[2af55c9]: https://github.com/Gallopsled/pwntools/commit/2af55c9bc382eca23f89bc0abc7a07c075521f94
|
||||
|
||||
## 3.1.1
|
||||
|
||||
Fixed a bug in `MemLeak.struct` (PR: #768).
|
||||
|
||||
## 3.1.0
|
||||
|
||||
A number of smaller bugfixes and documentation tweaks.
|
||||
|
||||
## 3.0.4
|
||||
|
||||
- Fixed a bug that made 3.0.3 uninstallable (Issue: #751, PR: #752)
|
||||
|
||||
## 3.0.3
|
||||
|
||||
- Fixed some performance and usability problems with the update system (Issues:
|
||||
#723, #724, #736. PRs: #729, #738, #747).
|
||||
- Fixed a bug related to internals in pyelftools (PRs: #730, #746).
|
||||
- Fixed an issue with travis (Issue: #741, PRs: #743, #744, #745).
|
||||
|
||||
## 3.0.2
|
||||
|
||||
- Cherry-pick #695, as this was a regression-fix.
|
||||
- Added a fix for the update checker, as it would suggest prereleases as updates to stable releases.
|
||||
- Various documentation fixes.
|
||||
|
||||
## 3.0.1
|
||||
|
||||
A small bugfix release. There were a lot of references to the `master`-branch, however after 3.0.0 we use the names `stable`, `beta` and `dev` for our branches.
|
||||
|
||||
## 3.0.0
|
||||
|
||||
This was a large release (1305 commits since 2.2.0) with a lot of bugfixes and changes. The Binjitsu project, a fork of Pwntools, was merged back into Pwntools. As such, its features are now available here.
|
||||
|
||||
@@ -38,8 +526,8 @@ Android support via a new `adb` module, `context.device`, `context.adb_host`, an
|
||||
- Added `context.log_file` setting for sending logs to a file. This can be set with the `LOG_FILE` magic command-line option.
|
||||
- Added `context.noptrace` setting for disabling actions which require `ptrace` support. This is useful for turning all `gdb.debug` and `gdb.attach` options into no-ops, and can be set via the `NOPTRACE` magic command-line option.
|
||||
- Added `context.proxy` which hooks all connections and sends them to a SOCKS4/SOCKS5. This can be set via the `PROXY` magic command-line option.
|
||||
- Added `context.randomize` to control randommization of settings like XOR keys and register ordering (default off).
|
||||
- Added `context.termianl` for setting how to launch commands in a new terminal.
|
||||
- Added `context.randomize` to control randomization of settings like XOR keys and register ordering (default off).
|
||||
- Added `context.terminal` for setting how to launch commands in a new terminal.
|
||||
|
||||
#### DynELF and MemLeak Module
|
||||
|
||||
@@ -51,7 +539,7 @@ Android support via a new `adb` module, `context.device`, `context.adb_host`, an
|
||||
#### Encoders Module
|
||||
|
||||
- Added a `pwnlib.encoders` module for assembled-shellcode encoders/decoders
|
||||
- Includes position-indepentent basic XOR encoders
|
||||
- Includes position-independent basic XOR encoders
|
||||
- Includes position-independent delta encoders
|
||||
- Includes non-position-independent alphanumeric encoders for Intel
|
||||
- Includes position-independent alphanumeric encoders for ARM/Thumb
|
||||
|
||||
+6
-1
@@ -19,9 +19,14 @@ Finally, it is probably a good idea to run the test suite locally before doing
|
||||
the pull-request to make sure everything works, however this is not a
|
||||
requirement.
|
||||
|
||||
Once you are ready to do a pull-request, you should figure out if your changes
|
||||
constitutes a new feature or a bugfix in stable or beta. If it is a bugfix in
|
||||
stable or beta, you should do the pull-request against the branch in question,
|
||||
and otherwise your pull-request should be against the dev branch.
|
||||
|
||||
Once you do the pull-request Travis CI will run the test-suite on it. Once it
|
||||
passes one of the core developers will look at your pull request, possibly
|
||||
comment on it and then hopefully merge it into master.
|
||||
comment on it and then hopefully merge it into the branch in question.
|
||||
|
||||
## Automated Testing
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ directories:
|
||||
- pwnlib/data/
|
||||
|
||||
|
||||
Copyright (c) 2015 Gallopsled and Zach Riggle
|
||||
Copyright (c) 2015 Gallopsled et al.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
+7
-1
@@ -1 +1,7 @@
|
||||
include *.txt
|
||||
graft examples
|
||||
graft extra
|
||||
include *.md *.txt *.sh *.yml MANIFEST.in
|
||||
recursive-include docs *.rst *.png Makefile *.py *.txt
|
||||
recursive-include pwnlib *.py *.asm *.rst *.md *.txt *.sh __doc__ *.mako
|
||||
recursive-include pwn *.py *.asm *.rst *.md *.txt *.sh
|
||||
recursive-exclude *.pyc
|
||||
@@ -1,16 +1,14 @@
|
||||
# pwntools - CTF toolkit
|
||||

|
||||

|
||||
|
||||
[](https://pwntools.readthedocs.org/)
|
||||
[](https://pwntools.readthedocs.org/en/2.2.0)
|
||||
[](https://pypi.python.org/pypi/pwntools/)
|
||||
[](https://www.gittip.com/gallopsled/)
|
||||
[](https://travis-ci.org/Gallopsled/pwntools)
|
||||
[](https://coveralls.io/github/Gallopsled/pwntools?branch=master)
|
||||
[](https://docs.pwntools.com/)
|
||||
[](https://pypi.python.org/pypi/pwntools/)
|
||||
[](https://travis-ci.org/Gallopsled/pwntools)
|
||||
[](https://coveralls.io/github/Gallopsled/pwntools?branch=dev)
|
||||
[](https://twitter.com/pwntools)
|
||||
[](http://choosealicense.com/licenses/mit/)
|
||||
|
||||
pwntools is a CTF framework and exploit development library. Written in Python, it is designed for rapid prototyping and development, and intended to make exploit writing as simple as possible.
|
||||
Pwntools is a CTF framework and exploit development library. Written in Python, it is designed for rapid prototyping and development, and intended to make exploit writing as simple as possible.
|
||||
|
||||
```python
|
||||
from pwn import *
|
||||
@@ -24,30 +22,28 @@ r.interactive()
|
||||
|
||||
# Try It Now!
|
||||
|
||||
You can now do a live demo of Pwntools, [right in your browser](http://demo.pwntools.com). Alternately, you can SSH to the same host, and log in as user `zerocool` with [this private key][key] (password `i_promise_not_to_be_evil`).
|
||||
|
||||
It will drop you into a clean, Docker-ized container. There is nothing of value on the VPS, so please don't be evil.
|
||||
|
||||
[key]: https://gist.githubusercontent.com/zachriggle/efa2e0080ae6de2e8344/raw/4b503e9db54f009d97477d03d4ba5678471f8ff0/id_rsa
|
||||
You can now do a live demo of Pwntools, [right in your browser](https://demo.pwntools.com).
|
||||
|
||||
# Documentation
|
||||
Our documentation is available at [pwntools.readthedocs.org](https://pwntools.readthedocs.org/)
|
||||
|
||||
Our documentation is available at [docs.pwntools.com](https://docs.pwntools.com/)
|
||||
|
||||
To get you started, we've provided some example solutions for past CTF challenges in our [write-ups repository](https://github.com/Gallopsled/pwntools-write-ups).
|
||||
|
||||
# Installation
|
||||
|
||||
pwntools is best supported on 64-bit Ubuntu 12.04 and 14.04, but most functionality should work on any Posix-like distribution (Debian, Arch, FreeBSD, OSX, etc.). Python 2.7 is required.
|
||||
Pwntools is best supported on 64-bit Ubuntu LTE releases (12.04, 14.04, and 16.04). Most functionality should work on any Posix-like distribution (Debian, Arch, FreeBSD, OSX, etc.). Python 2.7 is required.
|
||||
|
||||
Most of the functionality of pwntools is self-contained and Python-only. You should be able to get running quickly with
|
||||
|
||||
```sh
|
||||
apt-get update
|
||||
apt-get install python2.7 python-pip python-dev git libssl-dev
|
||||
pip install --upgrade git+https://github.com/Gallopsled/pwntools.git
|
||||
apt-get install python2.7 python-pip python-dev git libssl-dev libffi-dev build-essential
|
||||
pip install --upgrade pip
|
||||
pip install --upgrade pwntools
|
||||
```
|
||||
|
||||
However, some of the features (assembling/disassembling foreign architectures) require non-Python dependencies. For more information, see the [complete installation instructions here](https://pwntools.readthedocs.org/en/latest/install.html).
|
||||
However, some of the features (assembling/disassembling foreign architectures) require non-Python dependencies. For more information, see the [complete installation instructions here](https://docs.pwntools.com/en/stable/install.html).
|
||||
|
||||
|
||||
# Contribution
|
||||
|
||||
+11
-8
@@ -4,18 +4,21 @@ Pwntools makes extensive use of unit tests and integration tests to ensure every
|
||||
|
||||
## Test Suite
|
||||
|
||||
|
||||
To run the test suite, it is beste to use Ubuntu 12.04 or 14.04, and run the following commands. **Be aware** that this will add a user to the machine, and create a public key for SSH login!
|
||||
To run the test suite, it is best to use Ubuntu 12.04 or 14.04, and run the following commands. **Be aware** that this will add a user to the machine, and create a public key for SSH login!
|
||||
|
||||
```sh
|
||||
bash .travis_install.sh
|
||||
bash .travis_ssh_setup.sh
|
||||
pip install -e .
|
||||
pip install -r docs/requirements.txt
|
||||
cd docs
|
||||
PWNLIB_NOTERM=1 make clean doctest
|
||||
bash travis/install.sh
|
||||
bash travis/ssh_setup.sh
|
||||
pip install --upgrade --editable .
|
||||
PWNLIB_NOTERM=1 make -C docs doctest
|
||||
```
|
||||
|
||||
## Testing in Docker
|
||||
|
||||
A `Dockerfile` has been provided which has a clean testing environment with Ubuntu Xenial. It is very similar to the online Travis CI testing environment, but uses a more modern version of Ubuntu.
|
||||
|
||||
See `travis/docker/README.md` for more information.
|
||||
|
||||
## New Tests
|
||||
|
||||
To add a new test to an existing module, just add an inline doctest. If the test needs access to an external module, add the import statement to the `testsetup` block in the corresponding file in `docs/source/<module>.rst`.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
sphinxcontrib-napoleon
|
||||
sphinxcontrib-autoprogram
|
||||
sphinxcontrib-autoprogram==0.1.4
|
||||
isort
|
||||
paramiko>=1.15.2
|
||||
mako>=1.0.0
|
||||
@@ -14,3 +14,4 @@ pygments>=2.0
|
||||
sphinx_rtd_theme
|
||||
doc2dash
|
||||
coveralls
|
||||
sphinx<1.8.0
|
||||
+5
-1
@@ -1,9 +1,13 @@
|
||||
.. testsetup:: *
|
||||
|
||||
from pwn import *
|
||||
adb = pwnlib.adb
|
||||
|
||||
:mod:`pwnlib.adb` --- Android Debug Bridge
|
||||
=====================================================
|
||||
|
||||
.. automodule:: pwnlib.adb
|
||||
.. automodule:: pwnlib.adb.adb
|
||||
:members:
|
||||
|
||||
.. automodule:: pwnlib.adb.protocol
|
||||
:members:
|
||||
@@ -0,0 +1,9 @@
|
||||
.. testsetup:: *
|
||||
|
||||
from pwn import *
|
||||
|
||||
:mod:`pwnlib.args` --- Magic Command-Line Arguments
|
||||
=====================================================
|
||||
|
||||
.. automodule:: pwnlib.args
|
||||
:members:
|
||||
@@ -13,3 +13,13 @@
|
||||
|
||||
.. automodule:: pwnlib.asm
|
||||
:members:
|
||||
|
||||
Internal Functions
|
||||
-----------------------------------------
|
||||
|
||||
These are only included so that their tests are run.
|
||||
|
||||
You should never need these.
|
||||
|
||||
.. autofunction:: pwnlib.asm.dpkg_search_for_binutils
|
||||
.. autofunction:: pwnlib.asm.print_binutils_instructions
|
||||
@@ -14,45 +14,5 @@ pwntools comes with a handful of useful command-line utilities which serve as wr
|
||||
|
||||
.. toctree::
|
||||
|
||||
.. autoprogram:: pwnlib.commandline.asm:parser
|
||||
:prog: asm
|
||||
|
||||
.. autoprogram:: pwnlib.commandline.checksec:parser
|
||||
:prog: checksec
|
||||
|
||||
.. autoprogram:: pwnlib.commandline.constgrep:p
|
||||
:prog: constgrep
|
||||
|
||||
.. autoprogram:: pwnlib.commandline.cyclic:parser
|
||||
:prog: cyclic
|
||||
|
||||
.. autoprogram:: pwnlib.commandline.disasm:parser
|
||||
:prog: disasm
|
||||
|
||||
.. autoprogram:: pwnlib.commandline.elfdiff:p
|
||||
:prog: elfdiff
|
||||
|
||||
.. autoprogram:: pwnlib.commandline.elfpatch:p
|
||||
:prog: elfpatch
|
||||
|
||||
.. autoprogram:: pwnlib.commandline.errno:parser
|
||||
:prog: errno
|
||||
|
||||
.. autoprogram:: pwnlib.commandline.hex:parser
|
||||
:prog: hex
|
||||
|
||||
.. autoprogram:: pwnlib.commandline.phd:parser
|
||||
:prog: phd
|
||||
|
||||
.. autoprogram:: pwnlib.commandline.pwnstrip:p
|
||||
:prog: pwnstrip
|
||||
|
||||
.. autoprogram:: pwnlib.commandline.scramble:parser
|
||||
:prog: scramble
|
||||
|
||||
.. autoprogram:: pwnlib.commandline.shellcraft:p
|
||||
:prog: shellcraft
|
||||
|
||||
.. autoprogram:: pwnlib.commandline.unhex:parser
|
||||
:prog: unhex
|
||||
|
||||
.. autoprogram:: pwnlib.commandline.main:parser
|
||||
:prog: pwn
|
||||
+86
-8
@@ -24,8 +24,6 @@ sys.path.insert(0, os.path.abspath('../..'))
|
||||
|
||||
import pwnlib
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
|
||||
@@ -44,6 +42,27 @@ extensions = [
|
||||
'sphinxcontrib.napoleon'
|
||||
]
|
||||
|
||||
# Disable "info" logging directly to stdout by Sphinx
|
||||
import logging
|
||||
|
||||
class SphinxPwnlibFilter(logging.Filter):
|
||||
def filter(self, record):
|
||||
if record.name.startswith('pwn'):
|
||||
return False
|
||||
if record.name.startswith('paramiko'):
|
||||
return False
|
||||
return True
|
||||
|
||||
log_filter = SphinxPwnlibFilter()
|
||||
|
||||
for i, handler in enumerate(logging.root.handlers):
|
||||
print("Filtering Sphinx handler", handler)
|
||||
handler.addFilter(log_filter)
|
||||
|
||||
# Napoleon settings
|
||||
napoleon_use_ivar = True
|
||||
napoleon_use_rtype = False
|
||||
|
||||
doctest_global_setup = '''
|
||||
import sys, os
|
||||
os.environ['PWNLIB_NOTERM'] = '1'
|
||||
@@ -52,17 +71,29 @@ import pwnlib
|
||||
pwnlib.context.context.reset_local()
|
||||
pwnlib.context.ContextType.defaults['log_level'] = 'ERROR'
|
||||
pwnlib.context.ContextType.defaults['randomize'] = False
|
||||
pwnlib.util.fiddling.default_style = {}
|
||||
pwnlib.term.text.when = 'never'
|
||||
pwnlib.log.install_default_handler()
|
||||
pwnlib.log.rootlogger.setLevel(1)
|
||||
|
||||
# Sphinx modifies sys.stdout, and context.log_terminal has
|
||||
# a reference to the original instance. We need to update
|
||||
# it for logging to be captured.
|
||||
class stdout(object):
|
||||
def __getattr__(self, name):
|
||||
return getattr(sys.stdout, name)
|
||||
def __setattr__(self, name, value):
|
||||
return setattr(sys.stdout, name, value)
|
||||
pwnlib.context.ContextType.defaults['log_console'] = stdout()
|
||||
'''
|
||||
|
||||
autodoc_member_order = 'alphabetical'
|
||||
autoclass_content = 'both'
|
||||
autodoc_member_order = 'groupwise' # 'alphabetical'
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
doctest_test_doctest_blocks = True
|
||||
doctest_test_doctest_blocks = 'true'
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
@@ -75,7 +106,7 @@ master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'pwntools'
|
||||
copyright = u'2015, Zach Riggle'
|
||||
copyright = u'2016, Gallopsled et al.'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
@@ -217,11 +248,11 @@ latex_elements = {
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'pwntools.tex', u'pwntools Documentation',
|
||||
u'2015, Zach Riggle', 'manual'),
|
||||
u'2016, Gallopsled et al.', 'manual'),
|
||||
]
|
||||
|
||||
intersphinx_mapping = {'python': ('https://docs.python.org/2.7', None),
|
||||
'paramiko': ('https://paramiko-docs.readthedocs.org/en/1.15/', None)}
|
||||
'paramiko': ('https://paramiko-docs.readthedocs.org/en/2.1/', None)}
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
@@ -250,7 +281,7 @@ intersphinx_mapping = {'python': ('https://docs.python.org/2.7', None),
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'pwntools', u'pwntools Documentation',
|
||||
[u'2015, Zach Riggle'], 1)
|
||||
[u'2016, Gallopsled et al.'], 1)
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
@@ -337,3 +368,50 @@ if build_dash:
|
||||
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
|
||||
|
||||
# otherwise, readthedocs.org uses their theme by default, so no need to specify it
|
||||
|
||||
|
||||
# -- Customization to Sphinx autodoc generation --------------------------------------------
|
||||
import sphinx.ext.autodoc
|
||||
from sphinx.util.inspect import safe_getmembers, safe_getattr
|
||||
|
||||
# Test hidden members (e.g. def _foo(...))
|
||||
def dont_skip_any_doctests(app, what, name, obj, skip, options):
|
||||
return False
|
||||
|
||||
# Test non-exported members
|
||||
class ModuleDocumenter(sphinx.ext.autodoc.ModuleDocumenter):
|
||||
def get_object_members(self, want_all):
|
||||
if want_all:
|
||||
# if not hasattr(self.object, '__all__'):
|
||||
# for implicit module members, check __module__ to avoid
|
||||
# documenting imported objects
|
||||
return True, safe_getmembers(self.object)
|
||||
# else:
|
||||
# memberlist = self.object.__all__
|
||||
# # Sometimes __all__ is broken...
|
||||
# if not isinstance(memberlist, (list, tuple)) or not \
|
||||
# all(isinstance(entry, string_types) for entry in memberlist):
|
||||
# self.directive.warn(
|
||||
# '__all__ should be a list of strings, not %r '
|
||||
# '(in module %s) -- ignoring __all__' %
|
||||
# (memberlist, self.fullname))
|
||||
# # fall back to all members
|
||||
# return True, safe_getmembers(self.object)
|
||||
else:
|
||||
memberlist = self.options.members or []
|
||||
ret = []
|
||||
for mname in memberlist:
|
||||
try:
|
||||
ret.append((mname, safe_getattr(self.object, mname)))
|
||||
except AttributeError:
|
||||
self.directive.warn(
|
||||
'missing attribute mentioned in :members: or __all__: '
|
||||
'module %s, attribute %s' % (
|
||||
safe_getattr(self.object, '__name__', '???'), mname))
|
||||
return False, ret
|
||||
|
||||
if 'doctest' in sys.argv:
|
||||
def setup(app):
|
||||
app.connect('autodoc-skip-member', dont_skip_any_doctests)
|
||||
|
||||
sphinx.ext.autodoc.ModuleDocumenter = ModuleDocumenter
|
||||
@@ -0,0 +1,4 @@
|
||||
:mod:`pwnlib.config` --- Pwntools Configuration File
|
||||
====================================================
|
||||
|
||||
.. automodule:: pwnlib.config
|
||||
+22
-4
@@ -3,13 +3,31 @@
|
||||
from pwn import *
|
||||
import logging
|
||||
log = pwnlib.log.getLogger('pwnlib.context')
|
||||
context.clear()
|
||||
|
||||
:mod:`pwnlib.context` --- Setting runtime variables
|
||||
=====================================================
|
||||
|
||||
.. autodata:: pwnlib.context.context
|
||||
Many settings in ``pwntools`` are controlled via the global variable :data:`.context`, such as the selected target operating system, architecture, and bit-width.
|
||||
|
||||
.. autoclass:: pwnlib.context.ContextType
|
||||
:members:
|
||||
In general, exploits will start with something like:
|
||||
|
||||
.. autoclass:: pwnlib.context.Thread
|
||||
.. code-block:: python
|
||||
|
||||
from pwn import *
|
||||
context.arch = 'amd64'
|
||||
|
||||
Which sets up everything in the exploit for exploiting a 64-bit Intel binary.
|
||||
|
||||
The recommended method is to use ``context.binary`` to automagically set all of the appropriate values.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pwn import *
|
||||
context.binary = './challenge-binary'
|
||||
|
||||
Module Members
|
||||
----------------------------------------------------
|
||||
|
||||
.. automodule:: pwnlib.context
|
||||
:members:
|
||||
+11
-3
@@ -3,8 +3,16 @@
|
||||
from pwnlib.elf import *
|
||||
from pwnlib.util.misc import which
|
||||
|
||||
:mod:`pwnlib.elf` --- Working with ELF binaries
|
||||
===============================================
|
||||
:mod:`pwnlib.elf` --- ELF Executables and Libraries
|
||||
===================================================
|
||||
|
||||
.. automodule:: pwnlib.elf
|
||||
:members:
|
||||
|
||||
|
||||
ELF Modules
|
||||
-------------------
|
||||
|
||||
.. toctree::
|
||||
elf/elf
|
||||
elf/config
|
||||
elf/corefile
|
||||
@@ -0,0 +1,10 @@
|
||||
.. testsetup:: *
|
||||
|
||||
from pwn import *
|
||||
from pwnlib.elf.config import parse_kconfig
|
||||
|
||||
:mod:`pwnlib.elf.config` --- Kernel Config Parsing
|
||||
===========================================================
|
||||
|
||||
.. automodule:: pwnlib.elf.config
|
||||
:members:
|
||||
@@ -0,0 +1,16 @@
|
||||
.. testsetup:: *
|
||||
|
||||
from glob import glob
|
||||
from pwn import *
|
||||
|
||||
:mod:`pwnlib.elf.corefile` --- Core Files
|
||||
===========================================================
|
||||
|
||||
.. automodule:: pwnlib.elf.corefile
|
||||
|
||||
.. autoclass:: pwnlib.elf.corefile.Corefile
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: pwnlib.elf.corefile.Mapping
|
||||
:members:
|
||||
@@ -0,0 +1,28 @@
|
||||
.. testsetup:: *
|
||||
|
||||
from pwn import *
|
||||
from glob import glob
|
||||
|
||||
:mod:`pwnlib.elf.elf` --- ELF Files
|
||||
===========================================================
|
||||
|
||||
.. automodule:: pwnlib.elf.elf
|
||||
|
||||
.. autoclass:: pwnlib.elf.elf.ELF
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:inherited-members:
|
||||
:exclude-members: address_offsets,
|
||||
get_data,
|
||||
get_dwarf_info,
|
||||
get_section,
|
||||
get_segment,
|
||||
has_dwarf_info,
|
||||
iter_sections,
|
||||
iter_segments
|
||||
|
||||
.. autoclass:: pwnlib.elf.elf.Function
|
||||
:members:
|
||||
|
||||
.. autoclass:: pwnlib.elf.elf.dotdict
|
||||
:members:
|
||||
@@ -0,0 +1,10 @@
|
||||
.. testsetup:: *
|
||||
|
||||
from pwn import *
|
||||
|
||||
|
||||
:mod:`pwnlib.flag` --- CTF Flag Management
|
||||
==========================================
|
||||
|
||||
.. automodule:: pwnlib.flag
|
||||
:members:
|
||||
@@ -1,3 +1,7 @@
|
||||
.. testsetup:: *
|
||||
|
||||
from pwn import *
|
||||
|
||||
:mod:`pwnlib.gdb` --- Working with GDB
|
||||
======================================
|
||||
|
||||
|
||||
@@ -13,11 +13,11 @@ Which imports a bazillion things into the global namespace to make your life eas
|
||||
|
||||
This is a quick list of most of the objects and routines imported, in rough order of importance and frequency of use.
|
||||
|
||||
- ``context``
|
||||
- :mod:`pwnlib.context`
|
||||
- :data:`pwnlib.context.context`
|
||||
- Responsible for most of the pwntools convenience settings
|
||||
- Set `context.log_level = 'debug'` when troubleshooting your exploit
|
||||
- Scope-aware, so you can disable logging for a subsection of code via ``pwnlib.context.ContextType.local``
|
||||
- Scope-aware, so you can disable logging for a subsection of code via :meth:`.ContextType.local`
|
||||
- ``remote``, ``listen``, ``ssh``, ``process``
|
||||
- :mod:`pwnlib.tubes`
|
||||
- Super convenient wrappers around all of the common functionality for CTF challenges
|
||||
@@ -57,11 +57,11 @@ This is a quick list of most of the objects and routines imported, in rough orde
|
||||
- ``gdb.debug`` and ``gdb.attach``
|
||||
- :mod:`pwnlib.gdb`
|
||||
- Launch a binary under GDB and pop up a new terminal to interact with it. Automates setting breakpoints and makes iteration on exploits MUCH faster.
|
||||
- Alternately, attach to a running process given a PID, ``pwnlib.tubes`` object, or even just a socket that's connected to it
|
||||
- Alternately, attach to a running process given a PID, :mod:`pwnlib.tubes` object, or even just a socket that's connected to it
|
||||
- ``args``
|
||||
- Dictionary contining all-caps command-line arguments for quick access
|
||||
- Dictionary containing all-caps command-line arguments for quick access
|
||||
- Run via ``python foo.py REMOTE=1`` and ``args['REMOTE'] == '1'``.
|
||||
- Can also control logging verbosity and terminal fancyness
|
||||
- Can also control logging verbosity and terminal fanciness
|
||||
- `NOTERM`
|
||||
- `SILENT`
|
||||
- `DEBUG`
|
||||
@@ -78,7 +78,7 @@ This is a quick list of most of the objects and routines imported, in rough orde
|
||||
- It's the new ``getch``
|
||||
- ``safeeval``
|
||||
- :mod:`pwnlib.util.safeeval`
|
||||
- Functions for safely evalutaing python code without nasty side-effects.
|
||||
- Functions for safely evaluating python code without nasty side-effects.
|
||||
|
||||
These are all pretty self explanatory, but are useful to have in the global namespace.
|
||||
|
||||
|
||||
@@ -5,6 +5,20 @@ pwntools
|
||||
Written in Python, it is designed for rapid prototyping and development,
|
||||
and intended to make exploit writing as simple as possible.
|
||||
|
||||
The primary location for this documentation is at docs.pwntools.com_, which uses
|
||||
readthedocs_. It comes in three primary flavors:
|
||||
|
||||
- Stable_
|
||||
- Beta_
|
||||
- Dev_
|
||||
|
||||
.. _readthedocs: https://readthedocs.org
|
||||
.. _docs.pwntools.com: https://docs.pwntools.com
|
||||
.. _Stable: https://docs.pwntools.com/en/stable
|
||||
.. _Beta: https://docs.pwntools.com/en/beta
|
||||
.. _Dev: https://docs.pwntools.com/en/dev
|
||||
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
|
||||
@@ -29,19 +43,25 @@ Each of the ``pwntools`` modules is documented here.
|
||||
:glob:
|
||||
|
||||
adb
|
||||
args
|
||||
asm
|
||||
atexception
|
||||
atexit
|
||||
constants
|
||||
config
|
||||
context
|
||||
dynelf
|
||||
encoders
|
||||
elf
|
||||
exception
|
||||
flag
|
||||
fmtstr
|
||||
gdb
|
||||
libcdb
|
||||
log
|
||||
memleak
|
||||
protocols
|
||||
qemu
|
||||
replacements
|
||||
rop
|
||||
rop/*
|
||||
@@ -53,6 +73,7 @@ Each of the ``pwntools`` modules is documented here.
|
||||
tubes
|
||||
tubes/*
|
||||
ui
|
||||
update
|
||||
useragents
|
||||
util/*
|
||||
|
||||
|
||||
@@ -24,8 +24,10 @@ pwntools is available as a ``pip`` package.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ apt-get install python2.7 python2.7-dev python-pip
|
||||
$ pip install --upgrade git+https://github.com/Gallopsled/pwntools.git
|
||||
$ apt-get update
|
||||
$ apt-get install python2.7 python-pip python-dev git libssl-dev libffi-dev build-essential
|
||||
$ pip install --upgrade pip
|
||||
$ pip install --upgrade pwntools
|
||||
|
||||
Development
|
||||
--------------
|
||||
@@ -35,7 +37,6 @@ If you are hacking on Pwntools locally, you'll want to do something like this:
|
||||
.. code-block:: bash
|
||||
|
||||
$ git clone https://github.com/Gallopsled/pwntools
|
||||
$ cd pwntools
|
||||
$ pip install -e .
|
||||
$ pip install --upgrade --editable ./pwntools
|
||||
|
||||
.. _Ubuntu: https://launchpad.net/~pwntools/+archive/ubuntu/binutils
|
||||
@@ -11,7 +11,10 @@ Building `binutils` from source takes about 60 seconds on a modern 8-core machin
|
||||
|
||||
Ubuntu
|
||||
^^^^^^^^^^^^^^^^
|
||||
First, add our `Personal Package Archive repository <http://binutils.pwntools.com>`__.
|
||||
|
||||
For Ubuntu 12.04 through 15.10, you must first add the pwntools `Personal Package Archive repository <http://binutils.pwntools.com>`__.
|
||||
|
||||
Ubuntu Xenial (16.04) has official packages for most architectures, and does not require this step.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ This exposes a standard interface to talk to processes, sockets, serial ports,
|
||||
and all manner of things, along with some nifty helpers for common tasks.
|
||||
For example, remote connections via :mod:`pwnlib.tubes.remote`.
|
||||
|
||||
>>> conn = remote('ftp.debian.org',21)
|
||||
>>> conn = remote('ftp.ubuntu.com',21)
|
||||
>>> conn.recvline() # doctest: +ELLIPSIS
|
||||
'220 ...'
|
||||
>>> conn.send('USER anonymous\r\n')
|
||||
@@ -72,7 +72,7 @@ a ``process`` tube.
|
||||
|
||||
::
|
||||
|
||||
>>> shell = ssh('bandit0', 'bandit.labs.overthewire.org', password='bandit0')
|
||||
>>> shell = ssh('bandit0', 'bandit.labs.overthewire.org', password='bandit0', port=2220)
|
||||
>>> shell['whoami']
|
||||
'bandit0'
|
||||
>>> shell.download_file('/etc/motd')
|
||||
@@ -176,8 +176,8 @@ loaded with useful time-saving shellcodes.
|
||||
Let's say that we want to `setreuid(getuid(), getuid())` followed by `dup`ing
|
||||
file descriptor 4 to `stdin`, `stdout`, and `stderr`, and then pop a shell!
|
||||
|
||||
>>> asm(shellcraft.setreuid() + shellcraft.dupsh(4)).encode('hex')
|
||||
'6a3158cd8089c36a465889d9cd806a045b6a0359496a3f58cd8075f86a68682f2f2f73682f62696e6a0b5889e331c999cd80'
|
||||
>>> asm(shellcraft.setreuid() + shellcraft.dupsh(4)).encode('hex') # doctest: +ELLIPSIS
|
||||
'6a3158cd80...'
|
||||
|
||||
|
||||
Misc Tools
|
||||
@@ -212,8 +212,8 @@ Stop hard-coding things! Look them up at runtime with :mod:`pwnlib.elf`.
|
||||
You can even patch and save the files.
|
||||
|
||||
>>> e = ELF('/bin/cat')
|
||||
>>> e.read(e.address+1, 3)
|
||||
'ELF'
|
||||
>>> e.read(e.address, 4)
|
||||
'\x7fELF'
|
||||
>>> e.asm(e.address, 'ret')
|
||||
>>> e.save('/tmp/quiet-cat')
|
||||
>>> disasm(file('/tmp/quiet-cat','rb').read(1))
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
.. testsetup:: *
|
||||
|
||||
from pwn import *
|
||||
from pwnlib.libcdb import *
|
||||
|
||||
:mod:`pwnlib.libcdb` --- Libc Database
|
||||
===========================================
|
||||
|
||||
.. automodule:: pwnlib.libcdb
|
||||
:members:
|
||||
@@ -1,11 +1,9 @@
|
||||
.. testsetup:: *
|
||||
|
||||
from pwnlib.memleak import *
|
||||
from pwn import *
|
||||
|
||||
:mod:`pwnlib.memleak` --- Helper class for leaking memory
|
||||
=========================================================
|
||||
|
||||
.. module:: pwnlib.memleak
|
||||
|
||||
.. autoclass:: MemLeak
|
||||
:members:
|
||||
.. automodule:: pwnlib.memleak
|
||||
:members:
|
||||
@@ -0,0 +1,15 @@
|
||||
:mod:`pwnlib.protocols` --- Wire Protocols
|
||||
=============================================
|
||||
|
||||
.. automodule:: pwnlib.protocols
|
||||
|
||||
|
||||
Supported Protocols
|
||||
-------------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
:glob:
|
||||
|
||||
protocols/*
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
.. testsetup:: *
|
||||
|
||||
from pwn import *
|
||||
from pwnlib.protocols.adb import AdbClient
|
||||
|
||||
:mod:`pwnlib.protocols.adb` --- ADB Protocol Implementation
|
||||
===========================================================
|
||||
|
||||
.. automodule:: pwnlib.protocols.adb
|
||||
:members:
|
||||
@@ -0,0 +1,10 @@
|
||||
.. testsetup:: *
|
||||
|
||||
from pwn import *
|
||||
|
||||
|
||||
:mod:`pwnlib.qemu` --- QEMU Utilities
|
||||
==========================================
|
||||
|
||||
.. automodule:: pwnlib.qemu
|
||||
:members:
|
||||
@@ -0,0 +1,19 @@
|
||||
.. testsetup:: *
|
||||
|
||||
from pwn import *
|
||||
context.clear(arch='aarch64')
|
||||
|
||||
:mod:`pwnlib.shellcraft.aarch64` --- Shellcode for AArch64
|
||||
===========================================================
|
||||
|
||||
:mod:`pwnlib.shellcraft.aarch64`
|
||||
--------------------------------
|
||||
|
||||
.. automodule:: pwnlib.shellcraft.aarch64
|
||||
:members:
|
||||
|
||||
:mod:`pwnlib.shellcraft.aarch64.linux`
|
||||
--------------------------------------
|
||||
|
||||
.. automodule:: pwnlib.shellcraft.aarch64.linux
|
||||
:members:
|
||||
@@ -0,0 +1,19 @@
|
||||
.. testsetup:: *
|
||||
|
||||
from pwn import *
|
||||
context.clear(arch='mips')
|
||||
|
||||
:mod:`pwnlib.shellcraft.mips` --- Shellcode for MIPS
|
||||
===========================================================
|
||||
|
||||
:mod:`pwnlib.shellcraft.mips`
|
||||
-----------------------------
|
||||
|
||||
.. automodule:: pwnlib.shellcraft.mips
|
||||
:members:
|
||||
|
||||
:mod:`pwnlib.shellcraft.mips.linux`
|
||||
-----------------------------------
|
||||
|
||||
.. automodule:: pwnlib.shellcraft.mips.linux
|
||||
:members:
|
||||
@@ -27,4 +27,4 @@ Types of Tubes
|
||||
.. autoclass:: pwnlib.tubes.tube.tube()
|
||||
:members:
|
||||
:exclude-members: recv_raw, send_raw, settimeout_raw,
|
||||
can_recv_raw
|
||||
can_recv_raw, shutdown_raw, connected_raw,
|
||||
@@ -1,6 +1,7 @@
|
||||
.. testsetup:: *
|
||||
|
||||
from pwn import *
|
||||
from pwnlib.tubes.server import server
|
||||
|
||||
:mod:`pwnlib.tubes.sock` --- Sockets
|
||||
===========================================================
|
||||
@@ -23,3 +24,9 @@
|
||||
.. autoclass:: pwnlib.tubes.listen.listen
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
.. automodule:: pwnlib.tubes.server
|
||||
|
||||
.. autoclass:: pwnlib.tubes.server.server
|
||||
:members:
|
||||
:show-inheritance:
|
||||
@@ -0,0 +1,10 @@
|
||||
.. testsetup:: *
|
||||
|
||||
from pwn import *
|
||||
from pwnlib.update import *
|
||||
|
||||
:mod:`pwnlib.update` --- Updating Pwntools
|
||||
===================================================
|
||||
|
||||
.. automodule:: pwnlib.update
|
||||
:members:
|
||||
@@ -1,5 +1,6 @@
|
||||
.. testsetup:: *
|
||||
|
||||
from pwn import *
|
||||
from pwnlib.util.cyclic import *
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
.. testsetup:: *
|
||||
|
||||
from pwnlib.util.fiddling import *
|
||||
from pwn import *
|
||||
from pwnlib.util.fiddling import *
|
||||
|
||||
|
||||
:mod:`pwnlib.util.fiddling` --- Utilities bit fiddling
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
.. testsetup:: *
|
||||
|
||||
from pwnlib.util.safeeval import *
|
||||
_get_opcodes = pwnlib.util.safeeval._get_opcodes
|
||||
|
||||
|
||||
:mod:`pwnlib.util.safeeval` --- Safe evaluation of python code
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
.. testsetup:: *
|
||||
|
||||
from pwn import *
|
||||
test = pwnlib.util.sh_string.test
|
||||
|
||||
:mod:`pwnlib.util.sh_string` --- Shell Expansion is Hard
|
||||
===============================================================
|
||||
|
||||
.. automodule:: pwnlib.util.sh_string
|
||||
:members:
|
||||
+1
-1
@@ -4,7 +4,7 @@ the pwntools project.
|
||||
|
||||
We have a plan to create a separate repository with examples, primarily
|
||||
exploits. Until we do so, we recommend new users to look at
|
||||
https://pwntools.readthedocs.org, as this is a better overview of our features.
|
||||
https://docs.pwntools.com, as this is a better overview of our features.
|
||||
|
||||
In no particular order the docstrings for each example:
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ the pwntools project.
|
||||
|
||||
We have a plan to create a separate repository with examples, primarily
|
||||
exploits. Until we do so, we recommend new users to look at
|
||||
https://pwntools.readthedocs.org, as this is a better overview of our features.
|
||||
https://docs.pwntools.com, as this is a better overview of our features.
|
||||
|
||||
In no particular order the docstrings for each example:
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
from pwn import *
|
||||
context.arch='aarch64'
|
||||
frame = SigreturnFrame()
|
||||
|
||||
registers = ['x%i' % i for i in range(0, 31)]
|
||||
registers += ['sp', 'pc']
|
||||
|
||||
|
||||
for index, register in enumerate(registers):
|
||||
setattr(frame, register, index)
|
||||
|
||||
assembly = '\n'.join([
|
||||
shellcraft.read(constants.STDIN_FILENO, 'sp', 1024),
|
||||
shellcraft.syscall(constants.SYS_rt_sigreturn)
|
||||
])
|
||||
|
||||
binary = ELF.from_assembly(assembly)
|
||||
|
||||
io = binary.process()
|
||||
io.flat(frame)
|
||||
io.wait()
|
||||
assert io.poll() == -11
|
||||
|
||||
corefile = io.corefile
|
||||
|
||||
for index, register in enumerate(registers):
|
||||
value = getattr(corefile, register)
|
||||
if index != value:
|
||||
log.error("%s != %i (%i)" % (register, index, value))
|
||||
else:
|
||||
log.success("%s == %i" % (register, value))
|
||||
@@ -0,0 +1,32 @@
|
||||
from pwn import *
|
||||
context.arch='amd64'
|
||||
frame = SigreturnFrame()
|
||||
|
||||
registers = ['rax', 'rbx', 'rcx', 'rdx',
|
||||
'rdi', 'rsi', 'rbp', 'rsp',
|
||||
'rip',
|
||||
'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15']
|
||||
|
||||
for index, register in enumerate(registers):
|
||||
setattr(frame, register, index)
|
||||
|
||||
assembly = '\n'.join([
|
||||
shellcraft.read(constants.STDIN_FILENO, 'rsp', 1024),
|
||||
shellcraft.sigreturn()
|
||||
])
|
||||
|
||||
binary = ELF.from_assembly(assembly)
|
||||
|
||||
io = binary.process()
|
||||
io.flat(frame)
|
||||
io.wait()
|
||||
assert io.poll() == -11
|
||||
|
||||
corefile = io.corefile
|
||||
|
||||
for index, register in enumerate(registers):
|
||||
value = getattr(corefile, register)
|
||||
if index != value:
|
||||
log.error("%s != %i (%i)" % (register, index, value))
|
||||
else:
|
||||
log.success("%s == %i" % (register, value))
|
||||
@@ -0,0 +1,32 @@
|
||||
from pwn import *
|
||||
|
||||
context.arch='arm'
|
||||
frame = SigreturnFrame()
|
||||
|
||||
registers = ['r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7',
|
||||
'r8', 'r9', 'r10', 'fp', 'ip', 'sp', 'pc', 'lr']
|
||||
|
||||
|
||||
for index, register in enumerate(registers):
|
||||
setattr(frame, register, index)
|
||||
|
||||
assembly = '\n'.join([
|
||||
shellcraft.read(constants.STDIN_FILENO, 'sp', 1024),
|
||||
shellcraft.sigreturn()
|
||||
])
|
||||
|
||||
binary = ELF.from_assembly(assembly)
|
||||
|
||||
io = binary.process()
|
||||
io.flat(frame)
|
||||
io.wait()
|
||||
assert io.poll() == -11
|
||||
|
||||
corefile = io.corefile
|
||||
|
||||
for index, register in enumerate(registers):
|
||||
value = getattr(corefile, register)
|
||||
if index != value:
|
||||
log.error("%s != %i (%i)" % (register, index, value))
|
||||
else:
|
||||
log.success("%s == %i" % (register, value))
|
||||
@@ -0,0 +1,31 @@
|
||||
from pwn import *
|
||||
context.kernel='amd64'
|
||||
frame = SigreturnFrame()
|
||||
|
||||
registers = ['eax', 'ebx', 'ecx', 'edx',
|
||||
'edi', 'esi', 'ebp', 'esp',
|
||||
'eip']
|
||||
|
||||
for index, register in enumerate(registers):
|
||||
setattr(frame, register, index)
|
||||
|
||||
assembly = '\n'.join([
|
||||
shellcraft.read(constants.STDIN_FILENO, 'esp', 1024),
|
||||
shellcraft.sigreturn()
|
||||
])
|
||||
|
||||
binary = ELF.from_assembly(assembly)
|
||||
|
||||
io = binary.process()
|
||||
io.flat(frame)
|
||||
io.wait()
|
||||
assert io.poll() == -11
|
||||
|
||||
corefile = io.corefile
|
||||
|
||||
for index, register in enumerate(registers):
|
||||
value = getattr(corefile, register)
|
||||
if index != value:
|
||||
log.error("%s != %i (%i)" % (register, index, value))
|
||||
else:
|
||||
log.success("%s == %i" % (register, value))
|
||||
+1
-1
@@ -4,7 +4,7 @@ Example showing how to use the ssh class.
|
||||
|
||||
from pwn import *
|
||||
|
||||
shell = ssh(host='bandit.labs.overthewire.org',user='bandit0',password='bandit0')
|
||||
shell = ssh(host='bandit.labs.overthewire.org',user='bandit0',password='bandit0', port=2220)
|
||||
|
||||
# Show basic command syntax
|
||||
log.info("username: %s" % shell.whoami())
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
# cache list of shellcodes
|
||||
_shellcraft_shellcodes=$(shellcraft)
|
||||
_shellcraft_shellcodes=$(pwn shellcraft -l)
|
||||
|
||||
_shellcraft()
|
||||
{
|
||||
@@ -43,4 +44,5 @@ _shellcraft()
|
||||
COMPREPLY=( $(compgen -W "${_shellcraft_shellcodes}" -- ${cur}) )
|
||||
}
|
||||
|
||||
complete -F _shellcraft pwn shellcraft
|
||||
complete -F _shellcraft shellcraft
|
||||
@@ -1,58 +0,0 @@
|
||||
############################################################
|
||||
# Dockerfile to build Pwntools container
|
||||
# Based on Ubuntu
|
||||
############################################################
|
||||
|
||||
FROM ubuntu:trusty
|
||||
MAINTAINER Maintainer Zach Riggle
|
||||
|
||||
RUN apt-get update && apt-get install -y software-properties-common
|
||||
RUN apt-add-repository --yes ppa:pwntools/binutils
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y \
|
||||
binutils \
|
||||
binutils-aarch64-linux-gnu \
|
||||
binutils-arm-linux-gnueabihf \
|
||||
curl \
|
||||
gdb \
|
||||
gdbserver \
|
||||
gdb-multiarch \
|
||||
git \
|
||||
libc6-i386 \
|
||||
libc6-arm64-cross \
|
||||
libc6-armhf-cross \
|
||||
libc6-dev-i386 \
|
||||
libffi-dev \
|
||||
libglib2.0-dev \
|
||||
libncurses5-dev \
|
||||
libncursesw5-dev \
|
||||
ltrace \
|
||||
python-dev \
|
||||
python-pip \
|
||||
python3-pip \
|
||||
python2.7 \
|
||||
qemu \
|
||||
qemu-user-static \
|
||||
strace \
|
||||
tmux \
|
||||
wget
|
||||
RUN pip install --upgrade ipython
|
||||
RUN useradd -m zerocool
|
||||
RUN usermod -U zerocool
|
||||
|
||||
RUN mkdir -p /etc/qemu-binfmt
|
||||
RUN ln -s /usr/aarch64-linux-gnu /etc/qemu-binfmt/aarch64
|
||||
RUN ln -s /usr/arm-linux-gnueabihf /etc/qemu-binfmt/arm
|
||||
|
||||
RUN pip install --upgrade pip pycparser psutil python-ptrace
|
||||
RUN pip3 install --upgrade pip pycparser psutil python-ptrace
|
||||
|
||||
RUN pip install --upgrade git+https://github.com/Gallopsled/pwntools.git
|
||||
|
||||
RUN locale-gen en_US.UTF-8
|
||||
ENV LANG en_US.UTF-8
|
||||
ENV LANGUAGE en_US:en
|
||||
ENV LC_ALL en_US.UTF-8
|
||||
|
||||
RUN chown -R zerocool.zerocool /home/zerocool
|
||||
RUN chsh -s /bin/bash zerocool
|
||||
@@ -0,0 +1,13 @@
|
||||
subdirs=xenial stable $(wildcard */)
|
||||
makefiles=$(wildcard */Makefile)
|
||||
tags=base stable beta dev
|
||||
|
||||
all: $(makefiles) $(subdirs)
|
||||
|
||||
$(subdirs):
|
||||
docker build -t pwntools/pwntools:$(shell basename $(@)) "$@"
|
||||
|
||||
$(makefiles):
|
||||
make -C $(shell dirname $@)
|
||||
|
||||
.PHONY: all $(subdirs) $(makefiles)
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
xenial
|
||||
@@ -0,0 +1,6 @@
|
||||
FROM pwntools/pwntools:stable
|
||||
|
||||
USER root
|
||||
RUN pip install --upgrade git+https://github.com/Gallopsled/pwntools@beta
|
||||
RUN PWNLIB_NOTERM=1 pwn update
|
||||
USER pwntools
|
||||
@@ -0,0 +1,6 @@
|
||||
FROM pwntools/pwntools:stable
|
||||
|
||||
USER root
|
||||
RUN pip install --upgrade git+https://github.com/Gallopsled/pwntools@dev
|
||||
RUN PWNLIB_NOTERM=1 pwn update
|
||||
USER pwntools
|
||||
@@ -0,0 +1,26 @@
|
||||
############################################################
|
||||
# Dockerfile to build Pwntools container
|
||||
# Based on Ubuntu
|
||||
############################################################
|
||||
|
||||
FROM kalilinux/kali-linux-docker
|
||||
MAINTAINER Maintainer Gallopsled et al.
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y build-essential
|
||||
RUN apt-get install -y git
|
||||
RUN apt-get install -y libssl-dev
|
||||
RUN apt-get install -y libffi-dev
|
||||
RUN apt-get install -y python2.7
|
||||
RUN apt-get install -y python-pip
|
||||
RUN apt-get install -y python-dev
|
||||
RUN pip install --upgrade pip
|
||||
RUN python -m pip install --upgrade pwntools
|
||||
RUN PWNLIB_NOTERM=1 pwn update
|
||||
|
||||
RUN apt-get install -y sudo
|
||||
RUN useradd -m pwntools
|
||||
RUN passwd --delete --unlock pwntools
|
||||
RUN echo "pwntools ALL=(ALL:ALL) NOPASSWD: ALL" > /etc/sudoers.d/pwntools
|
||||
USER pwntools
|
||||
WORKDIR /home/pwntools
|
||||
@@ -0,0 +1,8 @@
|
||||
all: Dockerfile
|
||||
|
||||
Dockerfile: ../xenial/Dockerfile FORCE
|
||||
sed "s|ubuntu:xenial|kalilinux/kali-linux-docker|" < "$<" > "$@"
|
||||
|
||||
FORCE:
|
||||
|
||||
.PHONY: all
|
||||
@@ -0,0 +1,26 @@
|
||||
############################################################
|
||||
# Dockerfile to build Pwntools container
|
||||
# Based on Ubuntu
|
||||
############################################################
|
||||
|
||||
FROM ubuntu:precise
|
||||
MAINTAINER Maintainer Gallopsled et al.
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y build-essential
|
||||
RUN apt-get install -y git
|
||||
RUN apt-get install -y libssl-dev
|
||||
RUN apt-get install -y libffi-dev
|
||||
RUN apt-get install -y python2.7
|
||||
RUN apt-get install -y python-pip
|
||||
RUN apt-get install -y python-dev
|
||||
RUN pip install --upgrade pip
|
||||
RUN python -m pip install --upgrade pwntools
|
||||
RUN PWNLIB_NOTERM=1 pwn update
|
||||
|
||||
RUN apt-get install -y sudo
|
||||
RUN useradd -m pwntools
|
||||
RUN passwd --delete --unlock pwntools
|
||||
RUN echo "pwntools ALL=(ALL:ALL) NOPASSWD: ALL" > /etc/sudoers.d/pwntools
|
||||
USER pwntools
|
||||
WORKDIR /home/pwntools
|
||||
@@ -0,0 +1,8 @@
|
||||
all: Dockerfile
|
||||
|
||||
Dockerfile: ../xenial/Dockerfile FORCE
|
||||
sed "s|ubuntu:xenial|ubuntu:precise|" < "$<" > "$@"
|
||||
|
||||
FORCE:
|
||||
|
||||
.PHONY: all
|
||||
@@ -0,0 +1,6 @@
|
||||
FROM pwntools/pwntools:base
|
||||
|
||||
USER root
|
||||
RUN pip install --upgrade git+https://github.com/Gallopsled/pwntools@stable
|
||||
RUN PWNLIB_NOTERM=1 pwn update
|
||||
USER pwntools
|
||||
@@ -0,0 +1,26 @@
|
||||
############################################################
|
||||
# Dockerfile to build Pwntools container
|
||||
# Based on Ubuntu
|
||||
############################################################
|
||||
|
||||
FROM ubuntu:trusty
|
||||
MAINTAINER Maintainer Gallopsled et al.
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y build-essential
|
||||
RUN apt-get install -y git
|
||||
RUN apt-get install -y libssl-dev
|
||||
RUN apt-get install -y libffi-dev
|
||||
RUN apt-get install -y python2.7
|
||||
RUN apt-get install -y python-pip
|
||||
RUN apt-get install -y python-dev
|
||||
RUN pip install --upgrade pip
|
||||
RUN python -m pip install --upgrade pwntools
|
||||
RUN PWNLIB_NOTERM=1 pwn update
|
||||
|
||||
RUN apt-get install -y sudo
|
||||
RUN useradd -m pwntools
|
||||
RUN passwd --delete --unlock pwntools
|
||||
RUN echo "pwntools ALL=(ALL:ALL) NOPASSWD: ALL" > /etc/sudoers.d/pwntools
|
||||
USER pwntools
|
||||
WORKDIR /home/pwntools
|
||||
@@ -0,0 +1,8 @@
|
||||
all: Dockerfile
|
||||
|
||||
Dockerfile: ../xenial/Dockerfile FORCE
|
||||
sed "s|ubuntu:xenial|ubuntu:trusty|" < "$<" > "$@"
|
||||
|
||||
FORCE:
|
||||
|
||||
.PHONY: all
|
||||
@@ -0,0 +1,26 @@
|
||||
############################################################
|
||||
# Dockerfile to build Pwntools container
|
||||
# Based on Ubuntu
|
||||
############################################################
|
||||
|
||||
FROM ubuntu:xenial
|
||||
MAINTAINER Maintainer Gallopsled et al.
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y build-essential
|
||||
RUN apt-get install -y git
|
||||
RUN apt-get install -y libssl-dev
|
||||
RUN apt-get install -y libffi-dev
|
||||
RUN apt-get install -y python2.7
|
||||
RUN apt-get install -y python-pip
|
||||
RUN apt-get install -y python-dev
|
||||
RUN pip install --upgrade pip
|
||||
RUN python -m pip install --upgrade pwntools
|
||||
RUN PWNLIB_NOTERM=1 pwn update
|
||||
|
||||
RUN apt-get install -y sudo
|
||||
RUN useradd -m pwntools
|
||||
RUN passwd --delete --unlock pwntools
|
||||
RUN echo "pwntools ALL=(ALL:ALL) NOPASSWD: ALL" > /etc/sudoers.d/pwntools
|
||||
USER pwntools
|
||||
WORKDIR /home/pwntools
|
||||
+6
-2
@@ -1,8 +1,11 @@
|
||||
# Promote useful stuff to toplevel
|
||||
from .toplevel import *
|
||||
from __future__ import absolute_import
|
||||
|
||||
from pwn.toplevel import *
|
||||
|
||||
pwnlib.args.initialize()
|
||||
pwnlib.log.install_default_handler()
|
||||
pwnlib.config.initialize()
|
||||
|
||||
log = pwnlib.log.getLogger('pwnlib.exploit')
|
||||
args = pwnlib.args.args
|
||||
@@ -13,4 +16,5 @@ if not platform.architecture()[0].startswith('64'):
|
||||
See Gallopsled/pwntools#518 for more information."""
|
||||
log.warn_once('Pwntools does not support 32-bit Python. Use a 64-bit release.')
|
||||
|
||||
pwnlib.update.check_automatically()
|
||||
with context.local(log_console=sys.stderr):
|
||||
pwnlib.update.check_automatically()
|
||||
+13
-6
@@ -6,6 +6,7 @@ import operator
|
||||
import os
|
||||
import re
|
||||
import socks
|
||||
import signal
|
||||
import string
|
||||
import struct
|
||||
import subprocess
|
||||
@@ -14,6 +15,8 @@ import tempfile
|
||||
import threading
|
||||
import time
|
||||
|
||||
from pprint import pprint
|
||||
|
||||
import pwnlib
|
||||
from pwnlib import *
|
||||
from pwnlib.asm import *
|
||||
@@ -21,14 +24,15 @@ from pwnlib.context import Thread
|
||||
from pwnlib.context import context
|
||||
from pwnlib.dynelf import DynELF
|
||||
from pwnlib.encoders import *
|
||||
from pwnlib.elf import Core
|
||||
from pwnlib.elf import ELF
|
||||
from pwnlib.elf import load
|
||||
from pwnlib.elf.corefile import Core, Corefile, Coredump
|
||||
from pwnlib.elf.elf import ELF, load
|
||||
from pwnlib.encoders import *
|
||||
from pwnlib.exception import PwnlibException
|
||||
from pwnlib.gdb import attach, debug, debug_assembly, debug_shellcode
|
||||
from pwnlib.flag import *
|
||||
from pwnlib.fmtstr import FmtStr, fmtstr_payload
|
||||
from pwnlib.log import getLogger
|
||||
from pwnlib.memleak import MemLeak
|
||||
from pwnlib.memleak import MemLeak, RelativeMemLeak
|
||||
from pwnlib.regsort import *
|
||||
from pwnlib.replacements import *
|
||||
from pwnlib.rop import ROP
|
||||
@@ -36,9 +40,10 @@ from pwnlib.rop.srop import SigreturnFrame
|
||||
from pwnlib.runner import *
|
||||
from pwnlib.timeout import Timeout
|
||||
from pwnlib.tubes.listen import listen
|
||||
from pwnlib.tubes.process import process
|
||||
from pwnlib.tubes.remote import remote, tcp, udp
|
||||
from pwnlib.tubes.process import process, PTY, PIPE, STDOUT
|
||||
from pwnlib.tubes.remote import remote, tcp, udp, connect
|
||||
from pwnlib.tubes.serialtube import serialtube
|
||||
from pwnlib.tubes.server import server
|
||||
from pwnlib.tubes.ssh import ssh
|
||||
from pwnlib.tubes.tube import tube
|
||||
from pwnlib.ui import *
|
||||
@@ -47,6 +52,7 @@ from pwnlib.util import iters
|
||||
from pwnlib.util import net
|
||||
from pwnlib.util import proc
|
||||
from pwnlib.util import safeeval
|
||||
from pwnlib.util.crc import BitPolynom
|
||||
from pwnlib.util.cyclic import *
|
||||
from pwnlib.util.fiddling import *
|
||||
from pwnlib.util.getdents import *
|
||||
@@ -55,6 +61,7 @@ from pwnlib.util.lists import *
|
||||
from pwnlib.util.misc import *
|
||||
from pwnlib.util.packing import *
|
||||
from pwnlib.util.proc import pidof
|
||||
from pwnlib.util.sh_string import sh_string, sh_prepare, sh_command_with
|
||||
from pwnlib.util.splash import *
|
||||
from pwnlib.util.web import *
|
||||
|
||||
|
||||
+4
-1
@@ -1,6 +1,8 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
import importlib
|
||||
|
||||
from .version import __version__
|
||||
from pwnlib.version import __version__
|
||||
|
||||
version = __version__
|
||||
|
||||
@@ -12,6 +14,7 @@ __all__ = [
|
||||
'commandline',
|
||||
'constants',
|
||||
'context',
|
||||
'data',
|
||||
'dynelf',
|
||||
'encoders',
|
||||
'elf',
|
||||
|
||||
+46
-26
@@ -1,6 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from .context import LocalContext
|
||||
from .context import context
|
||||
from __future__ import absolute_import
|
||||
|
||||
from pwnlib.context import LocalContext
|
||||
from pwnlib.context import context
|
||||
|
||||
|
||||
class ABI(object):
|
||||
@@ -24,7 +26,8 @@ class ABI(object):
|
||||
#: Indicates that this ABI returns to the next address on the slot
|
||||
returns = True
|
||||
|
||||
def __init__(self, regs, align, minimum):
|
||||
def __init__(self, stack, regs, align, minimum):
|
||||
self.stack = stack
|
||||
self.register_arguments = regs
|
||||
self.arg_alignment = align
|
||||
self.stack_minimum = minimum
|
||||
@@ -32,35 +35,52 @@ class ABI(object):
|
||||
@staticmethod
|
||||
@LocalContext
|
||||
def default():
|
||||
if context.os == 'android':
|
||||
context.os = 'linux'
|
||||
|
||||
return {
|
||||
(32, 'i386', 'linux'): linux_i386,
|
||||
(64, 'aarch64', 'linux'): linux_aarch64,
|
||||
(64, 'amd64', 'linux'): linux_amd64,
|
||||
(32, 'arm', 'linux'): linux_arm,
|
||||
(32, 'thumb', 'linux'): linux_arm,
|
||||
(32, 'mips', 'linux'): linux_mips,
|
||||
(32, 'i386', 'windows'): windows_i386,
|
||||
(64, 'amd64', 'windows'): windows_amd64,
|
||||
(32, 'powerpc', 'linux'): linux_ppc,
|
||||
(64, 'powerpc', 'linux'): linux_ppc64,
|
||||
}[(context.bits, context.arch, context.os)]
|
||||
|
||||
@staticmethod
|
||||
@LocalContext
|
||||
def syscall():
|
||||
if context.os == 'android':
|
||||
context.os = 'linux'
|
||||
|
||||
return {
|
||||
(32, 'i386', 'linux'): linux_i386_syscall,
|
||||
(64, 'amd64', 'linux'): linux_amd64_syscall,
|
||||
(64, 'aarch64', 'linux'): linux_aarch64_syscall,
|
||||
(32, 'arm', 'linux'): linux_arm_syscall,
|
||||
(32, 'thumb', 'linux'): linux_arm_syscall,
|
||||
(32, 'mips', 'linux'): linux_mips_syscall,
|
||||
(64, 'aarch64', 'linux'): linux_aarch64_syscall,
|
||||
(32, 'powerpc', 'linux'): linux_ppc_syscall,
|
||||
(64, 'powerpc', 'linux'): linux_ppc64_syscall,
|
||||
}[(context.bits, context.arch, context.os)]
|
||||
|
||||
@staticmethod
|
||||
@LocalContext
|
||||
def sigreturn():
|
||||
if context.os == 'android':
|
||||
context.os = 'linux'
|
||||
|
||||
return {
|
||||
(32, 'i386', 'linux'): linux_i386_sigreturn,
|
||||
(64, 'amd64', 'linux'): linux_amd64_sigreturn,
|
||||
(32, 'arm', 'linux'): linux_arm_sigreturn,
|
||||
(32, 'thumb', 'linux'): linux_arm_sigreturn,
|
||||
(64, 'aarch64', 'linux'): linux_aarch64_sigreturn,
|
||||
}[(context.bits, context.arch, context.os)]
|
||||
|
||||
class SyscallABI(ABI):
|
||||
@@ -68,9 +88,9 @@ class SyscallABI(ABI):
|
||||
The syscall ABI treats the syscall number as the zeroth argument,
|
||||
which must be loaded into the specified register.
|
||||
"""
|
||||
def __init__(self, register_arguments, *a, **kw):
|
||||
super(SyscallABI, self).__init__(register_arguments, *a, **kw)
|
||||
self.syscall_register = register_arguments[0]
|
||||
def __init__(self, *a, **kw):
|
||||
super(SyscallABI, self).__init__(*a, **kw)
|
||||
self.syscall_register = self.register_arguments[0]
|
||||
|
||||
class SigreturnABI(SyscallABI):
|
||||
"""
|
||||
@@ -81,26 +101,26 @@ class SigreturnABI(SyscallABI):
|
||||
returns = False
|
||||
|
||||
|
||||
linux_i386 = ABI([], 4, 0)
|
||||
linux_amd64 = ABI(['rdi','rsi','rdx','rcx','r8','r9'], 8, 0)
|
||||
linux_arm = ABI(['r0', 'r1', 'r2', 'r3'], 8, 0)
|
||||
linux_aarch64 = ABI(['x0', 'x1', 'x2', 'x3'], 16, 0)
|
||||
linux_mips = ABI(['$a0','$a1','$a2','$a3'], 4, 0)
|
||||
linux_i386 = ABI('esp', [], 4, 0)
|
||||
linux_amd64 = ABI('rsp', ['rdi','rsi','rdx','rcx','r8','r9'], 8, 0)
|
||||
linux_arm = ABI('sp', ['r0', 'r1', 'r2', 'r3'], 8, 0)
|
||||
linux_aarch64 = ABI('sp', ['x0', 'x1', 'x2', 'x3'], 16, 0)
|
||||
linux_mips = ABI('$sp', ['$a0','$a1','$a2','$a3'], 4, 0)
|
||||
linux_ppc = ABI('sp', ['r3', 'r4', 'r5', 'r6', 'r7', 'r8', 'r9', 'r10'], 4, 0)
|
||||
linux_ppc64 = ABI('sp', ['r3', 'r4', 'r5', 'r6', 'r7', 'r8', 'r9', 'r10'], 8, 0)
|
||||
|
||||
linux_i386_syscall = SyscallABI(['eax', 'ebx', 'ecx', 'edx', 'esi', 'edi', 'ebp'], 4, 0)
|
||||
linux_amd64_syscall = SyscallABI(['rax','rdi', 'rsi', 'rdx', 'r10', 'r8', 'r9'], 8, 0)
|
||||
linux_arm_syscall = SyscallABI(['r7', 'r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6'], 4, 0)
|
||||
linux_aarch64_syscall = SyscallABI(['x8', 'x0', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6'], 16, 0)
|
||||
linux_mips_syscall = ABI(['$v0', '$a0','$a1','$a2','$a3'], 4, 0)
|
||||
linux_i386_syscall = SyscallABI('esp', ['eax', 'ebx', 'ecx', 'edx', 'esi', 'edi', 'ebp'], 4, 0)
|
||||
linux_amd64_syscall = SyscallABI('rsp', ['rax', 'rdi', 'rsi', 'rdx', 'r10', 'r8', 'r9'], 8, 0)
|
||||
linux_arm_syscall = SyscallABI('sp', ['r7', 'r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6'], 4, 0)
|
||||
linux_aarch64_syscall = SyscallABI('sp', ['x8', 'x0', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6'], 16, 0)
|
||||
linux_mips_syscall = SyscallABI('$sp', ['$v0','$a0','$a1','$a2','$a3'], 4, 0)
|
||||
linux_ppc_syscall = ABI('sp', ['r0', 'r3', 'r4', 'r5', 'r6', 'r7', 'r8', 'r9'], 4, 0)
|
||||
linux_ppc64_syscall = ABI('sp', ['r0', 'r3', 'r4', 'r5', 'r6', 'r7', 'r8', 'r9'], 8, 0)
|
||||
|
||||
linux_i386_sigreturn = SigreturnABI(['eax'], 4, 0)
|
||||
linux_amd64_sigreturn = SigreturnABI(['rax'], 4, 0)
|
||||
linux_arm_sigreturn = SigreturnABI(['r7'], 4, 0)
|
||||
linux_i386_sigreturn = SigreturnABI('esp', ['eax'], 4, 0)
|
||||
linux_amd64_sigreturn = SigreturnABI('rsp', ['rax'], 4, 0)
|
||||
linux_arm_sigreturn = SigreturnABI('sp', ['r7'], 4, 0)
|
||||
linux_aarch64_sigreturn = SigreturnABI('sp', ['x8'], 16, 0)
|
||||
|
||||
windows_i386 = ABI([], 4, 0)
|
||||
windows_amd64 = ABI(['rcx','rdx','r8','r9'], 32, 32)
|
||||
|
||||
# Fake ABIs used by SROP
|
||||
linux_i386_srop = ABI(['eax'], 4, 0)
|
||||
linux_amd64_srop = ABI(['rax'], 4, 0)
|
||||
linux_arm_srop = ABI(['r7'], 4, 0)
|
||||
windows_i386 = ABI('esp', [], 4, 0)
|
||||
windows_amd64 = ABI('rsp', ['rcx','rdx','r8','r9'], 32, 32)
|
||||
-723
@@ -1,723 +0,0 @@
|
||||
"""Provides utilities for interacting with Android devices via the Android Debug Bridge.
|
||||
"""
|
||||
import glob
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
import shutil
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
import dateutil.parser
|
||||
|
||||
from . import atexit
|
||||
from . import tubes
|
||||
from .context import context
|
||||
from .context import LocalContext
|
||||
from .device import Device
|
||||
from .log import getLogger
|
||||
from .util import misc
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
def adb(argv, *a, **kw):
|
||||
"""Returns the output of an ADB subcommand."""
|
||||
if isinstance(argv, (str, unicode)):
|
||||
argv = [argv]
|
||||
|
||||
log.debug("$ " + ' '.join(context.adb + argv))
|
||||
|
||||
return tubes.process.process(context.adb + argv, *a, **kw).recvall()
|
||||
|
||||
def root():
|
||||
"""Restarts adbd as root."""
|
||||
log.info("Enabling root on %s" % context.device)
|
||||
|
||||
with context.quiet:
|
||||
reply = adb('root')
|
||||
|
||||
if 'already running as root' in reply:
|
||||
return
|
||||
|
||||
elif not reply or 'restarting adbd as root' in reply:
|
||||
with context.quiet:
|
||||
wait_for_device()
|
||||
|
||||
else:
|
||||
log.error("Could not run as root:\n%s" % reply)
|
||||
|
||||
|
||||
def reboot(wait=True):
|
||||
"""Reboots the device."""
|
||||
log.info('Rebooting device %s' % context.device)
|
||||
|
||||
with context.quiet:
|
||||
adb('reboot')
|
||||
|
||||
if wait:
|
||||
wait_for_device()
|
||||
|
||||
def reboot_bootloader():
|
||||
"""Reboots the device to the bootloader."""
|
||||
log.info('Rebooting %s to bootloader' % context.device)
|
||||
|
||||
with context.quiet:
|
||||
adb('reboot-bootloader')
|
||||
|
||||
class AdbDevice(Device):
|
||||
"""Encapsulates information about a connected device."""
|
||||
def __init__(self, serial, type, port, product='unknown', model='unknown', device='unknown'):
|
||||
self.serial = serial
|
||||
self.type = type
|
||||
self.port = port
|
||||
self.product = product
|
||||
self.model = model.replace('_', ' ')
|
||||
self.device = device
|
||||
|
||||
if product == 'unknown':
|
||||
return
|
||||
|
||||
with context.local(device=serial):
|
||||
abi = str(properties.ro.product.cpu.abi)
|
||||
context.clear()
|
||||
context.arch = str(abi)
|
||||
self.arch = context.arch
|
||||
self.bits = context.bits
|
||||
self.endian = context.endian
|
||||
|
||||
def __str__(self):
|
||||
return self.serial
|
||||
|
||||
def __repr__(self):
|
||||
fields = ['serial', 'type', 'port', 'product', 'model', 'device']
|
||||
return '%s(%s)' % (self.__class__.__name__,
|
||||
', '.join(('%s=%r' % (field, getattr(self, field)) for field in fields)))
|
||||
|
||||
@staticmethod
|
||||
def from_adb_output(line):
|
||||
fields = line.split()
|
||||
|
||||
"""
|
||||
Example output:
|
||||
ZX1G22LM7G device usb:336789504X product:shamu model:Nexus_6 device:shamu features:cmd,shell_v2
|
||||
84B5T15A29020449 device usb:336855040X product:angler model:Nexus_6P device:angler
|
||||
0062741b0e54b353 unauthorized usb:337641472X
|
||||
"""
|
||||
|
||||
# The last few fields need to be split at colons.
|
||||
split = lambda x: x.split(':')[-1]
|
||||
fields[3:] = list(map(split, fields[3:]))
|
||||
|
||||
return AdbDevice(*fields[:6])
|
||||
|
||||
@context.quiet
|
||||
def devices(serial=None):
|
||||
"""Returns a list of ``Device`` objects corresponding to the connected devices."""
|
||||
lines = adb(['devices', '-l'])
|
||||
result = []
|
||||
|
||||
for line in lines.splitlines():
|
||||
# Skip the first 'List of devices attached' line, and the final empty line.
|
||||
if 'List of devices' in line or not line.strip():
|
||||
continue
|
||||
device = AdbDevice.from_adb_output(line)
|
||||
if device.serial == serial:
|
||||
return device
|
||||
result.append(device)
|
||||
|
||||
return tuple(result)
|
||||
|
||||
@LocalContext
|
||||
def wait_for_device(kick=False):
|
||||
"""Waits for a device to be connected."""
|
||||
with log.waitfor("Waiting for device to come online") as w:
|
||||
with context.quiet:
|
||||
if kick:
|
||||
try:
|
||||
adb(['reconnect'])
|
||||
except Exception:
|
||||
pass
|
||||
adb('wait-for-device')
|
||||
|
||||
for device in devices():
|
||||
if context.device == device:
|
||||
return device
|
||||
break
|
||||
else:
|
||||
log.error("Could not find any devices")
|
||||
|
||||
with context.local(device=device):
|
||||
# There may be multiple devices, so context.device is
|
||||
# insufficient. Pick the first device reported.
|
||||
w.success('%s (%s %s %s)' % (device,
|
||||
product(),
|
||||
build(),
|
||||
_build_date()))
|
||||
|
||||
return context.device
|
||||
|
||||
def disable_verity():
|
||||
"""Disables dm-verity on the device."""
|
||||
with log.waitfor("Disabling dm-verity on %s" % context.device) as w:
|
||||
root()
|
||||
|
||||
with context.quiet:
|
||||
reply = adb('disable-verity')
|
||||
|
||||
if 'Verity already disabled' in reply:
|
||||
return
|
||||
elif 'Now reboot your device' in reply:
|
||||
reboot(wait=True)
|
||||
else:
|
||||
log.error("Could not disable verity:\n%s" % reply)
|
||||
|
||||
|
||||
def remount():
|
||||
"""Remounts the filesystem as writable."""
|
||||
with log.waitfor("Remounting filesystem on %s" % context.device) as w:
|
||||
disable_verity()
|
||||
root()
|
||||
|
||||
with context.quiet:
|
||||
reply = adb('remount')
|
||||
|
||||
if 'remount succeeded' not in reply:
|
||||
log.error("Could not remount filesystem:\n%s" % reply)
|
||||
|
||||
def unroot():
|
||||
"""Restarts adbd as AID_SHELL."""
|
||||
log.info("Unrooting %s" % context.device)
|
||||
with context.quiet:
|
||||
reply = adb('unroot')
|
||||
|
||||
if 'restarting adbd as non root' not in reply:
|
||||
log.error("Could not run as root:\n%s" % reply)
|
||||
|
||||
def pull(remote_path, local_path=None):
|
||||
"""Download a file from the device.
|
||||
|
||||
Arguments:
|
||||
remote_path(str): Path or directory of the file on the device.
|
||||
local_path(str): Path to save the file to.
|
||||
Uses the file's name by default.
|
||||
"""
|
||||
if local_path is None:
|
||||
local_path = os.path.basename(remote_path)
|
||||
|
||||
msg = "Pulling %r from %r" % (remote_path, local_path)
|
||||
|
||||
if context.log_level == 'debug':
|
||||
msg += ' (%s)' % context.device
|
||||
|
||||
result = ''
|
||||
with log.waitfor(msg) as w:
|
||||
with context.quiet:
|
||||
args = context.adb + ['pull', remote_path, local_path]
|
||||
io = tubes.process.process(args)
|
||||
result = io.recvall()
|
||||
|
||||
if 0 != io.poll(block=True):
|
||||
log.error(result)
|
||||
|
||||
return result
|
||||
|
||||
def push(local_path, remote_path):
|
||||
"""Upload a file to the device.
|
||||
|
||||
Arguments:
|
||||
local_path(str): Path to the local file to push.
|
||||
remote_path(str): Path or directory to store the file on the device.
|
||||
"""
|
||||
msg = "Pushing %r to %r" % (local_path, remote_path)
|
||||
|
||||
if context.log_level == 'debug':
|
||||
msg += ' (%s)' % context.device
|
||||
|
||||
with log.waitfor(msg) as w:
|
||||
with context.quiet:
|
||||
args = context.adb + ['push', local_path, remote_path]
|
||||
io = tubes.process.process(args)
|
||||
result = io.recvall()
|
||||
|
||||
if 0 != io.poll(block=True):
|
||||
log.error(result)
|
||||
|
||||
return result
|
||||
|
||||
@context.quiet
|
||||
def read(path, target=None):
|
||||
"""Download a file from the device, and extract its contents.
|
||||
|
||||
Arguments:
|
||||
path(str): Path to the file on the device.
|
||||
target(str): Optional, location to store the file.
|
||||
Uses a temporary file by default.
|
||||
"""
|
||||
with tempfile.NamedTemporaryFile() as temp:
|
||||
target = target or temp.name
|
||||
pull(path, target)
|
||||
result = misc.read(target)
|
||||
return result
|
||||
|
||||
@context.quiet
|
||||
def write(path, data=''):
|
||||
"""Create a file on the device with the provided contents.
|
||||
|
||||
Arguments:
|
||||
path(str): Path to the file on the device
|
||||
data(str): Contents to store in the file
|
||||
"""
|
||||
with tempfile.NamedTemporaryFile() as temp:
|
||||
misc.write(temp.name, data)
|
||||
push(temp.name, path)
|
||||
|
||||
def process(argv, *a, **kw):
|
||||
"""Execute a process on the device.
|
||||
|
||||
See ``pwnlib.tubes.process.process`` documentation for more info.
|
||||
|
||||
Returns:
|
||||
A ``process`` tube.
|
||||
"""
|
||||
argv = argv or []
|
||||
if isinstance(argv, (str, unicode)):
|
||||
argv = [argv]
|
||||
|
||||
display = argv
|
||||
argv = context.adb + ['shell'] + argv
|
||||
|
||||
kw.setdefault('display', display)
|
||||
kw.setdefault('where', 'Android')
|
||||
|
||||
return tubes.process.process(argv, *a, **kw)
|
||||
|
||||
def interactive(**kw):
|
||||
"""Spawns an interactive shell."""
|
||||
return shell(**kw).interactive()
|
||||
|
||||
def shell(**kw):
|
||||
"""Returns an interactive shell."""
|
||||
return process([], **kw)
|
||||
|
||||
@context.quiet
|
||||
def which(name):
|
||||
"""Retrieves the full path to a binary in ``PATH`` on the device"""
|
||||
return process(['which', name]).recvall().strip()
|
||||
|
||||
def whoami():
|
||||
return process(['whoami']).recvall().strip()
|
||||
|
||||
def forward(port):
|
||||
"""Sets up a port to forward to the device."""
|
||||
tcp_port = 'tcp:%s' % port
|
||||
start_forwarding = adb(['forward', tcp_port, tcp_port])
|
||||
atexit.register(lambda: adb(['forward', '--remove', tcp_port]))
|
||||
|
||||
@context.quiet
|
||||
def logcat(stream=False):
|
||||
"""Reads the system log file.
|
||||
|
||||
By default, causes logcat to exit after reading the file.
|
||||
|
||||
Arguments:
|
||||
stream(bool): If ``True``, the contents are streamed rather than
|
||||
read in a one-shot manner. Default is ``False``.
|
||||
|
||||
Returns:
|
||||
If ``stream`` is ``False``, returns a string containing the log data.
|
||||
Otherwise, it returns a ``tube`` connected to the log output.
|
||||
"""
|
||||
|
||||
if stream:
|
||||
return process(['logcat'])
|
||||
else:
|
||||
return adb(['logcat', '-d'])
|
||||
|
||||
def pidof(name):
|
||||
"""Returns a list of PIDs for the named process."""
|
||||
with context.quiet:
|
||||
io = process(['pidof', name])
|
||||
data = io.recvall().split()
|
||||
return list(map(int, data))
|
||||
|
||||
def proc_exe(pid):
|
||||
"""Returns the full path of the executable for the provided PID."""
|
||||
with context.quiet:
|
||||
io = process(['readlink','-e','/proc/%d/exe' % pid])
|
||||
data = io.recvall().strip()
|
||||
return data
|
||||
|
||||
def getprop(name=None):
|
||||
"""Reads a properties from the system property store.
|
||||
|
||||
Arguments:
|
||||
name(str): Optional, read a single property.
|
||||
|
||||
Returns:
|
||||
If ``name`` is not specified, a ``dict`` of all properties is returned.
|
||||
Otherwise, a string is returned with the contents of the named property.
|
||||
"""
|
||||
with context.quiet:
|
||||
if name:
|
||||
return process(['getprop', name]).recvall().strip()
|
||||
|
||||
|
||||
result = process(['getprop']).recvall()
|
||||
|
||||
expr = r'\[([^\]]+)\]: \[(.*)\]'
|
||||
|
||||
props = {}
|
||||
|
||||
for line in result.splitlines():
|
||||
if not line.startswith('['):
|
||||
continue
|
||||
|
||||
name, value = re.search(expr, line).groups()
|
||||
|
||||
if value.isdigit():
|
||||
value = int(value)
|
||||
|
||||
props[name] = value
|
||||
|
||||
return props
|
||||
|
||||
def setprop(name, value):
|
||||
"""Writes a property to the system property store."""
|
||||
return process(['setprop', name, value]).recvall().strip()
|
||||
|
||||
def listdir(directory='/'):
|
||||
"""Returns a list containing the entries in the provided directory.
|
||||
|
||||
Note:
|
||||
Because ``adb shell`` is used to retrieve the listing, shell
|
||||
environment variable expansion and globbing are in effect.
|
||||
"""
|
||||
io = process(['find', directory, '-maxdepth', '1', '-print0'])
|
||||
data = io.recvall()
|
||||
paths = filter(len, data.split('\x00'))
|
||||
relpaths = [os.path.relpath(path, directory) for path in paths]
|
||||
if '.' in relpaths:
|
||||
relpaths.remove('.')
|
||||
return relpaths
|
||||
|
||||
def fastboot(args, *a, **kw):
|
||||
"""Executes a fastboot command.
|
||||
|
||||
Returns:
|
||||
The command output.
|
||||
"""
|
||||
serial = context.device
|
||||
if not serial:
|
||||
log.error("Unknown device")
|
||||
return tubes.process.process(['fastboot', '-s', serial] + list(args), **kw).recvall()
|
||||
|
||||
def fingerprint():
|
||||
"""Returns the device build fingerprint."""
|
||||
return str(properties.ro.build.fingerprint)
|
||||
|
||||
def product():
|
||||
"""Returns the device product identifier."""
|
||||
return str(properties.ro.build.product)
|
||||
|
||||
def build():
|
||||
"""Returns the Build ID of the device."""
|
||||
return str(properties.ro.build.id)
|
||||
|
||||
def unlock_bootloader():
|
||||
"""Unlocks the bootloader of the device.
|
||||
|
||||
Note:
|
||||
This requires physical interaction with the device.
|
||||
"""
|
||||
adb(['reboot-bootloader'])
|
||||
fastboot(['oem', 'unlock'])
|
||||
fastboot(['continue'])
|
||||
|
||||
class Kernel(object):
|
||||
_kallsyms = None
|
||||
|
||||
@property
|
||||
def address(self):
|
||||
return self.symbols['_text']
|
||||
|
||||
@property
|
||||
@context.quiet
|
||||
def symbols(self):
|
||||
"""Returns a dictionary of kernel symbols"""
|
||||
result = {}
|
||||
for line in self.kallsyms.splitlines():
|
||||
fields = line.split()
|
||||
address = int(fields[0], 16)
|
||||
name = fields[-1]
|
||||
result[name] = address
|
||||
return result
|
||||
|
||||
@property
|
||||
@context.quiet
|
||||
def kallsyms(self):
|
||||
"""Returns the raw output of kallsyms"""
|
||||
if not self._kallsyms:
|
||||
self._kallsyms = {}
|
||||
root()
|
||||
write('/proc/sys/kernel/kptr_restrict', '1')
|
||||
self._kallsyms = read('/proc/kallsyms')
|
||||
return self._kallsyms
|
||||
|
||||
@property
|
||||
@context.quiet
|
||||
def version(self):
|
||||
"""Returns the kernel version of the device."""
|
||||
root()
|
||||
return read('/proc/version').strip()
|
||||
|
||||
@property
|
||||
@context.quiet
|
||||
def cmdline(self):
|
||||
root()
|
||||
return read('/proc/cmdline').strip()
|
||||
|
||||
@property
|
||||
@context.quiet
|
||||
def lastmsg(self):
|
||||
root()
|
||||
if 'last_kmsg' in listdir('/proc'):
|
||||
return read('/proc/last_kmsg')
|
||||
|
||||
if 'console-ramoops' in listdir('/sys/fs/pstore/'):
|
||||
return read('/sys/fs/pstore/console-ramoops')
|
||||
|
||||
def enable_uart(self):
|
||||
"""Reboots the device with kernel logging to the UART enabled."""
|
||||
model = str(properties.ro.product.model)
|
||||
|
||||
known_commands = {
|
||||
'Nexus 4': None,
|
||||
'Nexus 5': None,
|
||||
'Nexus 6': 'oem config console enable',
|
||||
'Nexus 5X': None,
|
||||
'Nexus 6P': 'oem uart enable',
|
||||
'Nexus 7': 'oem uart-on',
|
||||
}
|
||||
|
||||
with log.waitfor('Enabling kernel UART') as w:
|
||||
|
||||
if model not in known_commands:
|
||||
log.error("Device UART is unsupported.")
|
||||
|
||||
command = known_commands[model]
|
||||
|
||||
if command is None:
|
||||
w.success('Always enabled')
|
||||
return
|
||||
|
||||
# Check the current commandline, it may already be enabled.
|
||||
if any(s.startswith('console=tty') for s in self.cmdline.split()):
|
||||
w.success("Already enabled")
|
||||
return
|
||||
|
||||
# Need to be root
|
||||
with context.local(device=context.device):
|
||||
# Save off the command line before rebooting to the bootloader
|
||||
cmdline = kernel.cmdline
|
||||
|
||||
reboot_bootloader()
|
||||
|
||||
# Wait for device to come online
|
||||
while context.device not in fastboot(['devices',' -l']):
|
||||
time.sleep(0.5)
|
||||
|
||||
# Try the 'new' way
|
||||
fastboot(command.split())
|
||||
fastboot(['continue'])
|
||||
wait_for_device()
|
||||
|
||||
|
||||
kernel = Kernel()
|
||||
|
||||
class Property(object):
|
||||
def __init__(self, name=None):
|
||||
self.__dict__['_name'] = name
|
||||
|
||||
def __str__(self):
|
||||
return getprop(self._name).strip()
|
||||
|
||||
def __repr__(self):
|
||||
return repr(str(self))
|
||||
|
||||
def __getattr__(self, attr):
|
||||
if self._name:
|
||||
attr = '%s.%s' % (self._name, attr)
|
||||
return Property(attr)
|
||||
|
||||
def __setattr__(self, attr, value):
|
||||
if attr in self.__dict__:
|
||||
return super(Property, self).__setattr__(attr, value)
|
||||
|
||||
if self._name:
|
||||
attr = '%s.%s' % (self._name, attr)
|
||||
setprop(attr, value)
|
||||
|
||||
properties = Property()
|
||||
|
||||
def _build_date():
|
||||
"""Returns the build date in the form YYYY-MM-DD as a string"""
|
||||
as_string = getprop('ro.build.date')
|
||||
as_datetime = dateutil.parser.parse(as_string)
|
||||
return as_datetime.strftime('%Y-%b-%d')
|
||||
|
||||
def find_ndk_project_root(source):
|
||||
'''Given a directory path, find the topmost project root.
|
||||
|
||||
tl;dr "foo/bar/jni/baz.cpp" ==> "foo/bar"
|
||||
'''
|
||||
ndk_directory = os.path.abspath(source)
|
||||
while ndk_directory != '/':
|
||||
if os.path.exists(os.path.join(ndk_directory, 'jni')):
|
||||
break
|
||||
ndk_directory = os.path.dirname(ndk_directory)
|
||||
else:
|
||||
return None
|
||||
|
||||
return ndk_directory
|
||||
|
||||
_android_mk_template = '''
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := poc
|
||||
LOCAL_SRC_FILES := %(local_src_files)s
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
'''.lstrip()
|
||||
|
||||
_application_mk_template = '''
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
APP_ABI:= %(app_abi)s
|
||||
APP_PLATFORM:=%(app_platform)s
|
||||
'''.lstrip()
|
||||
|
||||
def _generate_ndk_project(file_list, abi='arm-v7a', platform_version=21):
|
||||
# Create our project root
|
||||
root = tempfile.mkdtemp()
|
||||
|
||||
if not isinstance(file_list, (list, tuple)):
|
||||
file_list = [file_list]
|
||||
|
||||
# Copy over the source file(s)
|
||||
jni_directory = os.path.join(root, 'jni')
|
||||
os.mkdir(jni_directory)
|
||||
for file in file_list:
|
||||
shutil.copy(file, jni_directory)
|
||||
|
||||
# Create the directories
|
||||
|
||||
# Populate Android.mk
|
||||
local_src_files = ' '.join(list(map(os.path.basename, file_list)))
|
||||
Android_mk = os.path.join(jni_directory, 'Android.mk')
|
||||
with open(Android_mk, 'w+') as f:
|
||||
f.write(_android_mk_template % locals())
|
||||
|
||||
# Populate Application.mk
|
||||
app_abi = abi
|
||||
app_platform = 'android-%s' % platform_version
|
||||
Application_mk = os.path.join(jni_directory, 'Application.mk')
|
||||
with open(Application_mk, 'w+') as f:
|
||||
f.write(_application_mk_template % locals())
|
||||
|
||||
return root
|
||||
|
||||
def compile(source):
|
||||
"""Compile a source file or project with the Android NDK."""
|
||||
|
||||
# Ensure that we can find the NDK.
|
||||
ndk = os.environ.get('NDK', None)
|
||||
if ndk is None:
|
||||
log.error('$NDK must be set to the Android NDK directory')
|
||||
ndk_build = os.path.join(ndk, 'ndk-build')
|
||||
|
||||
# Determine whether the source is an NDK project or a single source file.
|
||||
project = find_ndk_project_root(source)
|
||||
|
||||
if not project:
|
||||
project = _generate_ndk_project(source,
|
||||
str(properties.ro.product.cpu.abi),
|
||||
str(properties.ro.build.version.sdk))
|
||||
|
||||
# Remove any output files
|
||||
lib = os.path.join(project, 'libs')
|
||||
if os.path.exists(lib):
|
||||
shutil.rmtree(lib)
|
||||
|
||||
# Build the project
|
||||
io = tubes.process.process(ndk_build, cwd=os.path.join(project, 'jni'))
|
||||
|
||||
result = io.recvall()
|
||||
|
||||
if 0 != io.poll():
|
||||
log.error("Build failed:\n%s" % result)
|
||||
|
||||
# Find all of the output files
|
||||
output = glob.glob(os.path.join(lib, '*', '*'))
|
||||
|
||||
return output[0]
|
||||
|
||||
class Partition(object):
|
||||
def __init__(self, path, name, blocks=0):
|
||||
self.path = path
|
||||
self.name = name
|
||||
self.blocks = blocks
|
||||
self.size = blocks * 1024
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
with log.waitfor('Fetching %r partition (%s)' % (self.name, self.path)):
|
||||
return read(self.path)
|
||||
|
||||
class Partitions(object):
|
||||
@property
|
||||
@context.quiet
|
||||
def by_name_dir(self):
|
||||
cmd = ['shell','find /dev/block/platform -type d -name by-name']
|
||||
return adb(cmd).strip()
|
||||
|
||||
@context.quiet
|
||||
def __dir__(self):
|
||||
return list(self)
|
||||
|
||||
@context.quiet
|
||||
def __iter__(self):
|
||||
root()
|
||||
|
||||
# Find all named partitions
|
||||
for name in listdir(self.by_name_dir):
|
||||
yield name
|
||||
|
||||
@context.quiet
|
||||
def __getattr__(self, attr):
|
||||
for name in self:
|
||||
if name == attr:
|
||||
break
|
||||
else:
|
||||
raise AttributeError("No partition %r" % attr)
|
||||
|
||||
path = os.path.join(self.by_name_dir, name)
|
||||
|
||||
# Find the actual path of the device
|
||||
devpath = process(['readlink', '-n', path]).recvall()
|
||||
devname = os.path.basename(devpath)
|
||||
|
||||
# Get the size of the partition
|
||||
for line in read('/proc/partitions').splitlines():
|
||||
if not line.strip():
|
||||
continue
|
||||
major, minor, blocks, name = line.split(None, 4)
|
||||
if devname == name:
|
||||
break
|
||||
else:
|
||||
log.error("Could not find size of partition %r" % name)
|
||||
|
||||
return Partition(devpath, attr, int(blocks))
|
||||
|
||||
partitions = Partitions()
|
||||
@@ -0,0 +1,4 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from pwnlib.adb.adb import *
|
||||
from pwnlib.adb.protocol import Client
|
||||
+1384
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,103 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import ctypes
|
||||
import io
|
||||
import os
|
||||
import sys
|
||||
|
||||
class img_info(ctypes.Structure):
|
||||
_fields_ = [
|
||||
('name', ctypes.c_char * 64),
|
||||
('size', ctypes.c_uint32)
|
||||
]
|
||||
|
||||
class bootloader_images_header(ctypes.Structure):
|
||||
_fields_ = [
|
||||
('magic', ctypes.c_char * 8),
|
||||
('num_images', ctypes.c_uint32),
|
||||
('start_offset', ctypes.c_uint32),
|
||||
('bootldr_size', ctypes.c_uint32),
|
||||
]
|
||||
|
||||
def __init__(self, *a, **kw):
|
||||
super(bootloader_images_header, self).__init__(*a, **kw)
|
||||
if self.magic != self.MAGIC:
|
||||
raise ValueError("Incorrect magic (%r, expected %r)" % (self.magic, self.MAGIC))
|
||||
MAGIC = 'BOOTLDR!'
|
||||
|
||||
class BootloaderImage(object):
|
||||
def __init__(self, data):
|
||||
"""Android Bootloader image
|
||||
|
||||
Arguments:
|
||||
data(str): Binary data from the image file.
|
||||
"""
|
||||
self.data = data
|
||||
self.header = bootloader_images_header.from_buffer_copy(data)
|
||||
|
||||
imgarray = ctypes.ARRAY(img_info, self.header.num_images)
|
||||
self.img_info = imgarray.from_buffer_copy(data, ctypes.sizeof(self.header))
|
||||
|
||||
def extract(self, index_or_name):
|
||||
"""extract(index_or_name) -> bytes
|
||||
|
||||
Extract the contents of an image.
|
||||
|
||||
Arguments:
|
||||
index_or_name(str,int): Either an image index or name.
|
||||
|
||||
Returns:
|
||||
Contents of the image.
|
||||
"""
|
||||
if isinstance(index_or_name, int):
|
||||
index = index_or_name
|
||||
else:
|
||||
for i in range(len(self.img_info)):
|
||||
if self.img_info[i].name == index_or_name:
|
||||
index = i
|
||||
break
|
||||
else:
|
||||
raise ValueError("Invalid img name: %r" % index_or_name)
|
||||
|
||||
if index >= len(self.img_info):
|
||||
raise ValueError("index out of range (%s, max %s)" % (index, len(self.img_info)))
|
||||
|
||||
offset = self.header.start_offset
|
||||
|
||||
for i in range(index):
|
||||
offset += self.img_info[i].size
|
||||
|
||||
return self.data[offset:offset + self.img_info[index].size]
|
||||
|
||||
def extract_all(self, path):
|
||||
"""extract_all(path)
|
||||
|
||||
Extracts all images to the provided path. The filenames are taken
|
||||
from the image name, with '.img' appended.
|
||||
"""
|
||||
if not os.path.isdir(path):
|
||||
raise ValueError("%r does not exist or is not a directory" % path)
|
||||
|
||||
for img in self.img_info:
|
||||
imgpath = os.path.join(path, img.name + '.img')
|
||||
with open(imgpath, 'wb+') as f:
|
||||
data = self.extract(img.name)
|
||||
f.write(data)
|
||||
|
||||
def __str__(self):
|
||||
rv = []
|
||||
rv.append("Bootloader")
|
||||
rv.append(" Magic: %r" % self.header.magic)
|
||||
rv.append(" Offset: %#x" % self.header.start_offset)
|
||||
rv.append(" Size: %#x" % self.header.bootldr_size)
|
||||
rv.append(" Images: %s" % self.header.num_images)
|
||||
for img in self.img_info:
|
||||
rv.append(" Name: %s" % img.name)
|
||||
rv.append(" Size: %#x" % img.size)
|
||||
rv.append(" Data: %r..." % self.extract(img.name)[:32])
|
||||
return '\n'.join(rv)
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Easy sanity checking
|
||||
b = BootloaderImage(open(sys.argv[1]).read())
|
||||
print(b)
|
||||
@@ -0,0 +1,5 @@
|
||||
"""
|
||||
This file exists only for backward compatibility
|
||||
"""
|
||||
from pwnlib.protocols.adb import AdbClient
|
||||
Client = AdbClient
|
||||
+111
-24
@@ -1,18 +1,84 @@
|
||||
|
||||
#!/usr/bin/env python2
|
||||
"""
|
||||
Pwntools exposes several magic command-line arguments and environment
|
||||
variables when operating in `from pwn import *` mode.
|
||||
|
||||
The arguments extracted from the command-line and removed from ``sys.argv``.
|
||||
|
||||
Arguments can be set by appending them to the command-line, or setting
|
||||
them in the environment prefixed by ``PWNLIB_``.
|
||||
|
||||
The easiest example is to enable more verbose debugging. Just set ``DEBUG``.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ PWNLIB_DEBUG=1 python exploit.py
|
||||
$ python exploit.py DEBUG
|
||||
|
||||
These arguments are automatically extracted, regardless of their name, and
|
||||
exposed via :mod:`pwnlib.args.args`, which is exposed as the global variable
|
||||
:data:`args`. Arguments which ``pwntools`` reserves internally are not exposed
|
||||
this way.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python -c 'from pwn import *; print args' A=1 B=Hello HOST=1.2.3.4 DEBUG
|
||||
defaultdict(<type 'str'>, {'A': '1', 'HOST': '1.2.3.4', 'B': 'Hello'})
|
||||
|
||||
This is very useful for conditional code, for example determining whether to
|
||||
run an exploit locally or to connect to a remote server. Arguments which are
|
||||
not specified evaluate to an empty string.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
if args['REMOTE']:
|
||||
io = remote('exploitme.com', 4141)
|
||||
else:
|
||||
io = process('./pwnable')
|
||||
|
||||
Arguments can also be accessed directly with the dot operator, e.g.:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
if args.REMOTE:
|
||||
...
|
||||
|
||||
Any undefined arguments evaluate to an empty string, ``''``.
|
||||
|
||||
The full list of supported "magic arguments" and their effects are listed
|
||||
below.
|
||||
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
import collections
|
||||
import logging
|
||||
import os
|
||||
import string
|
||||
import sys
|
||||
|
||||
from . import term
|
||||
from .context import context
|
||||
from pwnlib import term
|
||||
from pwnlib.context import context
|
||||
|
||||
class PwnlibArgs(collections.defaultdict):
|
||||
def __getattr__(self, attr):
|
||||
return self[attr]
|
||||
|
||||
args = PwnlibArgs(str)
|
||||
term_mode = True
|
||||
args = collections.defaultdict(str)
|
||||
env_prefix = 'PWNLIB_'
|
||||
free_form = True
|
||||
|
||||
# Check to see if we were invoked as one of the 'pwn xxx' scripts.
|
||||
# If so, we don't want to remove e.g. "SYS_" from the end of the command
|
||||
# line, as this breaks things like constgrep.
|
||||
import pwnlib.commandline
|
||||
basename = os.path.basename(sys.argv[0])
|
||||
|
||||
if basename == 'pwn' or basename in pwnlib.commandline.__all__:
|
||||
free_form = False
|
||||
|
||||
|
||||
def isident(s):
|
||||
"""
|
||||
@@ -42,46 +108,67 @@ def asbool(s):
|
||||
else:
|
||||
raise ValueError('must be integer or boolean: %r' % s)
|
||||
|
||||
def set_log_level(x):
|
||||
def LOG_LEVEL(x):
|
||||
"""Sets the logging verbosity used via ``context.log_level``,
|
||||
e.g. ``LOG_LEVEL=debug``.
|
||||
"""
|
||||
with context.local(log_level=x):
|
||||
context.defaults['log_level']=context.log_level
|
||||
|
||||
def set_log_file(x):
|
||||
def LOG_FILE(x):
|
||||
"""Sets a log file to be used via ``context.log_file``, e.g.
|
||||
``LOG_FILE=./log.txt``"""
|
||||
context.log_file=x
|
||||
|
||||
def set_log_level_error(x):
|
||||
set_log_level('error')
|
||||
def SILENT(x):
|
||||
"""Sets the logging verbosity to ``error`` which silences most
|
||||
output."""
|
||||
LOG_LEVEL('error')
|
||||
|
||||
def set_log_level_debug(x):
|
||||
set_log_level('debug')
|
||||
def DEBUG(x):
|
||||
"""Sets the logging verbosity to ``debug`` which displays much
|
||||
more information, including logging each byte sent by tubes."""
|
||||
LOG_LEVEL('debug')
|
||||
|
||||
def set_noterm(v):
|
||||
def NOTERM(v):
|
||||
"""Disables pretty terminal settings and animations."""
|
||||
if asbool(v):
|
||||
global term_mode
|
||||
term_mode = False
|
||||
|
||||
def set_timeout(v):
|
||||
def TIMEOUT(v):
|
||||
"""Sets a timeout for tube operations (in seconds) via
|
||||
``context.timeout``, e.g. ``TIMEOUT=30``"""
|
||||
context.defaults['timeout'] = int(v)
|
||||
|
||||
def set_randomize(v):
|
||||
def RANDOMIZE(v):
|
||||
"""Enables randomization of various pieces via ``context.randomize``"""
|
||||
context.defaults['randomize'] = asbool(v)
|
||||
|
||||
def set_aslr(v):
|
||||
def NOASLR(v):
|
||||
"""Disables ASLR via ``context.aslr``"""
|
||||
context.defaults['aslr'] = not asbool(v)
|
||||
|
||||
def set_noptrace(v):
|
||||
def NOPTRACE(v):
|
||||
"""Disables facilities which require ``ptrace`` such as ``gdb.attach()``
|
||||
statements, via ``context.noptrace``."""
|
||||
context.defaults['noptrace'] = asbool(v)
|
||||
|
||||
def STDERR(v):
|
||||
"""Sends logging to ``stderr`` by default, instead of ``stdout``"""
|
||||
context.log_console = sys.stderr
|
||||
|
||||
hooks = {
|
||||
'LOG_LEVEL': set_log_level,
|
||||
'LOG_FILE': set_log_file,
|
||||
'DEBUG': set_log_level_debug,
|
||||
'NOTERM': set_noterm,
|
||||
'SILENT': set_log_level_error,
|
||||
'RANDOMIZE': set_randomize,
|
||||
'TIMEOUT': set_timeout,
|
||||
'NOASLR': set_aslr,
|
||||
'NOPTRACE': set_noptrace,
|
||||
'LOG_LEVEL': LOG_LEVEL,
|
||||
'LOG_FILE': LOG_FILE,
|
||||
'DEBUG': DEBUG,
|
||||
'NOTERM': NOTERM,
|
||||
'SILENT': SILENT,
|
||||
'RANDOMIZE': RANDOMIZE,
|
||||
'TIMEOUT': TIMEOUT,
|
||||
'NOASLR': NOASLR,
|
||||
'NOPTRACE': NOPTRACE,
|
||||
'STDERR': STDERR,
|
||||
}
|
||||
|
||||
def initialize():
|
||||
@@ -113,7 +200,7 @@ def initialize():
|
||||
sys.argv.remove(orig)
|
||||
hooks[arg](value)
|
||||
|
||||
elif isident(arg):
|
||||
elif free_form and isident(arg):
|
||||
sys.argv.remove(orig)
|
||||
args[arg] = value
|
||||
|
||||
|
||||
+211
-96
@@ -27,8 +27,8 @@ Assembly
|
||||
Finally, :func:`asm` is used to assemble shellcode provided by ``pwntools``
|
||||
in the :mod:`shellcraft` module.
|
||||
|
||||
>>> asm(shellcraft.sh())
|
||||
'jhh///sh/binj\x0bX\x89\xe31\xc9\x99\xcd\x80'
|
||||
>>> asm(shellcraft.nop())
|
||||
'\x90'
|
||||
|
||||
Disassembly
|
||||
------------------------
|
||||
@@ -39,6 +39,8 @@ Disassembly
|
||||
' 0: b8 0b 00 00 00 mov eax,0xb'
|
||||
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
import errno
|
||||
import os
|
||||
import platform
|
||||
@@ -53,11 +55,11 @@ from glob import glob
|
||||
from os import environ
|
||||
from os import path
|
||||
|
||||
from . import atexit
|
||||
from . import shellcraft
|
||||
from .context import LocalContext
|
||||
from .context import context
|
||||
from .log import getLogger
|
||||
from pwnlib import atexit
|
||||
from pwnlib import shellcraft
|
||||
from pwnlib.context import LocalContext
|
||||
from pwnlib.context import context
|
||||
from pwnlib.log import getLogger
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
@@ -66,6 +68,75 @@ __all__ = ['asm', 'cpp', 'disasm', 'make_elf', 'make_elf_from_assembly']
|
||||
_basedir = path.split(__file__)[0]
|
||||
_incdir = path.join(_basedir, 'data', 'includes')
|
||||
|
||||
def dpkg_search_for_binutils(arch, util):
|
||||
"""Use dpkg to search for any available assemblers which will work.
|
||||
|
||||
Returns:
|
||||
A list of candidate package names.
|
||||
|
||||
::
|
||||
|
||||
>>> pwnlib.asm.dpkg_search_for_binutils('aarch64', 'as')
|
||||
['binutils-aarch64-linux-gnu']
|
||||
"""
|
||||
|
||||
# Example output:
|
||||
# $ dpkg -S 'arm*linux*-as'
|
||||
# binutils-arm-linux-gnu: /usr/bin/arm-linux-gnu-as
|
||||
# binutils-arm-linux-gnueabihf: /usr/bin/arm-linux-gnueabihf-as
|
||||
# binutils-arm-linux-gnueabihf: /usr/x86_64-linux-gnu/arm-linux-gnueabihf/include/dis-asm.h
|
||||
# binutils-arm-linux-gnu: /usr/x86_64-linux-gnu/arm-linux-gnu/include/dis-asm.h
|
||||
packages = []
|
||||
|
||||
try:
|
||||
filename = 'bin/%s*linux*-%s' % (arch, util)
|
||||
output = subprocess.check_output(['dpkg','-S',filename])
|
||||
for line in output.strip().splitlines():
|
||||
package, path = line.split(':', 1)
|
||||
packages.append(package)
|
||||
except OSError:
|
||||
pass
|
||||
except subprocess.CalledProcessError:
|
||||
pass
|
||||
|
||||
return packages
|
||||
|
||||
def print_binutils_instructions(util, context):
|
||||
"""On failure to find a binutils utility, inform the user of a way
|
||||
they can get it easily.
|
||||
|
||||
Doctest:
|
||||
|
||||
>>> context.clear(arch = 'amd64')
|
||||
>>> pwnlib.asm.print_binutils_instructions('as', context)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
PwnlibException: Could not find 'as' installed for ContextType(arch = 'amd64', bits = 64, endian = 'little')
|
||||
Try installing binutils for this architecture:
|
||||
$ sudo apt-get install binutils
|
||||
"""
|
||||
# This links to our instructions on how to manually install binutils
|
||||
# for several architectures.
|
||||
instructions = 'https://docs.pwntools.com/en/stable/install/binutils.html'
|
||||
|
||||
# However, if we can directly provide a useful command, go for it.
|
||||
binutils_arch = {
|
||||
'amd64': 'x86_64',
|
||||
'arm': 'armeabi',
|
||||
'thumb': 'armeabi',
|
||||
}.get(context.arch, context.arch)
|
||||
|
||||
packages = dpkg_search_for_binutils(binutils_arch, util)
|
||||
|
||||
if packages:
|
||||
instructions = '$ sudo apt-get install %s' % packages[0]
|
||||
|
||||
log.error("""
|
||||
Could not find %(util)r installed for %(context)s
|
||||
Try installing binutils for this architecture:
|
||||
%(instructions)s
|
||||
""".strip() % locals())
|
||||
|
||||
@LocalContext
|
||||
def which_binutils(util):
|
||||
"""
|
||||
@@ -75,8 +146,9 @@ def which_binutils(util):
|
||||
Examples:
|
||||
|
||||
>>> import platform
|
||||
>>> which_binutils = pwnlib.asm.which_binutils
|
||||
>>> which_binutils('as', arch=platform.machine())
|
||||
'.../bin/as'
|
||||
'.../bin/...as'
|
||||
>>> which_binutils('as', arch='arm') #doctest: +ELLIPSIS
|
||||
'.../bin/arm-...-as'
|
||||
>>> which_binutils('as', arch='powerpc') #doctest: +ELLIPSIS
|
||||
@@ -119,23 +191,20 @@ def which_binutils(util):
|
||||
for arch in arches:
|
||||
for gutil in utils:
|
||||
# e.g. objdump
|
||||
if arch is None: pattern = gutil
|
||||
if arch is None:
|
||||
pattern = gutil
|
||||
|
||||
# e.g. aarch64-linux-gnu-objdump
|
||||
else: pattern = '%s*linux*-%s' % (arch,gutil)
|
||||
else:
|
||||
pattern = '%s*linux*-%s' % (arch,gutil)
|
||||
|
||||
for dir in environ['PATH'].split(':'):
|
||||
res = sorted(glob(path.join(dir, pattern)))
|
||||
if res:
|
||||
return res[0]
|
||||
|
||||
locals()['context'] = context
|
||||
log.warning("""
|
||||
Could not find %(util)r installed for %(context)s
|
||||
Try installing binutils for this architecture:
|
||||
https://pwntools.readthedocs.org/en/latest/install/binutils.html
|
||||
""".strip() % locals())
|
||||
raise Exception('Could not find %(util)r installed for %(context)s' % locals())
|
||||
# No dice!
|
||||
print_binutils_instructions(util, context)
|
||||
|
||||
checked_assembler_version = defaultdict(lambda: False)
|
||||
|
||||
@@ -179,7 +248,7 @@ def _assembler():
|
||||
version = re.search(r' (\d\.\d+)', result).group(1)
|
||||
if version < '2.19':
|
||||
log.warn_once('Your binutils version is too old and may not work!\n' + \
|
||||
'Try updating with: https://pwntools.readthedocs.org/en/latest/install/binutils.html\n' + \
|
||||
'Try updating with: https://docs.pwntools.com/en/stable/install/binutils.html\n' + \
|
||||
'Reported Version: %r' % result.strip())
|
||||
|
||||
|
||||
@@ -331,16 +400,14 @@ def cpp(shellcode):
|
||||
|
||||
Examples:
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> cpp("mov al, SYS_setresuid", arch = "i386", os = "linux")
|
||||
'mov al, 164\n'
|
||||
>>> cpp("weee SYS_setresuid", arch = "arm", os = "linux")
|
||||
'weee (0+164)\n'
|
||||
>>> cpp("SYS_setresuid", arch = "thumb", os = "linux")
|
||||
'(0+164)\n'
|
||||
>>> cpp("SYS_setresuid", os = "freebsd")
|
||||
'311\n'
|
||||
>>> cpp("mov al, SYS_setresuid", arch = "i386", os = "linux")
|
||||
'mov al, 164\n'
|
||||
>>> cpp("weee SYS_setresuid", arch = "arm", os = "linux")
|
||||
'weee (0+164)\n'
|
||||
>>> cpp("SYS_setresuid", arch = "thumb", os = "linux")
|
||||
'(0+164)\n'
|
||||
>>> cpp("SYS_setresuid", os = "freebsd")
|
||||
'311\n'
|
||||
"""
|
||||
arch = context.arch
|
||||
os = context.os
|
||||
@@ -357,17 +424,39 @@ def cpp(shellcode):
|
||||
return _run(cmd, code).strip('\n').rstrip() + '\n'
|
||||
|
||||
@LocalContext
|
||||
def make_elf_from_assembly(assembly, vma = None, extract=False, shared = False):
|
||||
r"""
|
||||
Builds an ELF file with the specified assembly as its
|
||||
executable code.
|
||||
def make_elf_from_assembly(assembly,
|
||||
vma=None,
|
||||
extract=False,
|
||||
shared=False,
|
||||
strip=False,
|
||||
**kwargs):
|
||||
r"""make_elf_from_assembly(assembly, vma=None, extract=None, shared=False, strip=False, **kwargs) -> str
|
||||
|
||||
Builds an ELF file with the specified assembly as its executable code.
|
||||
|
||||
This differs from :func:`.make_elf` in that all ELF symbols are preserved,
|
||||
such as labels and local variables. Use :func:`.make_elf` if size matters.
|
||||
Additionally, the default value for ``extract`` in :func:`.make_elf` is
|
||||
different.
|
||||
|
||||
Note:
|
||||
This is effectively a wrapper around :func:`.asm`. with setting
|
||||
``extract=False``, ``vma=0x10000000``, and marking the resulting
|
||||
file as executable (``chmod +x``).
|
||||
|
||||
Note:
|
||||
ELF files created with `arch=thumb` will prepend an ARM stub
|
||||
which switches to Thumb mode.
|
||||
|
||||
Arguments:
|
||||
|
||||
assembly(str): Assembly
|
||||
assembly(str): Assembly code to build into an ELF
|
||||
vma(int): Load address of the binary
|
||||
extract(bool): Whether to return the data extracted from the file created,
|
||||
or the path to it.
|
||||
(Default: ``0x10000000``, or ``0`` if ``shared=True``)
|
||||
extract(bool): Extract the full ELF data from the file.
|
||||
(Default: ``False``)
|
||||
shared(bool): Create a shared library
|
||||
(Default: ``False``)
|
||||
kwargs(dict): Arguments to pass to :func:`.asm`.
|
||||
|
||||
Returns:
|
||||
|
||||
@@ -376,6 +465,9 @@ def make_elf_from_assembly(assembly, vma = None, extract=False, shared = False):
|
||||
|
||||
Example:
|
||||
|
||||
This example shows how to create a shared library, and load it via
|
||||
``LD_PRELOAD``.
|
||||
|
||||
>>> context.clear()
|
||||
>>> context.arch = 'amd64'
|
||||
>>> sc = 'push rbp; mov rbp, rsp;'
|
||||
@@ -384,6 +476,18 @@ def make_elf_from_assembly(assembly, vma = None, extract=False, shared = False):
|
||||
>>> solib = make_elf_from_assembly(sc, shared=1)
|
||||
>>> subprocess.check_output(['echo', 'World'], env={'LD_PRELOAD': solib})
|
||||
'Hello\nWorld\n'
|
||||
|
||||
The same thing can be done with :func:`.make_elf`, though the sizes
|
||||
are different. They both
|
||||
|
||||
>>> file_a = make_elf(asm('nop'), extract=True)
|
||||
>>> file_b = make_elf_from_assembly('nop', extract=True)
|
||||
>>> file_a[:4] == file_b[:4]
|
||||
True
|
||||
>>> len(file_a) < 0x200
|
||||
True
|
||||
>>> len(file_b) > 0x1000
|
||||
True
|
||||
"""
|
||||
if shared and vma:
|
||||
log.error("Cannot specify a VMA for a shared library.")
|
||||
@@ -400,38 +504,44 @@ def make_elf_from_assembly(assembly, vma = None, extract=False, shared = False):
|
||||
if not assembly.startswith(to_thumb):
|
||||
assembly = to_thumb + assembly
|
||||
|
||||
path = asm(assembly, vma = vma, extract = extract, shared = shared)
|
||||
result = asm(assembly, vma = vma, shared = shared, extract = False, **kwargs)
|
||||
|
||||
if not extract:
|
||||
os.chmod(path, 0755)
|
||||
os.chmod(result, 0755)
|
||||
else:
|
||||
with open(result, 'rb') as io:
|
||||
result = io.read()
|
||||
|
||||
return path
|
||||
return result
|
||||
|
||||
@LocalContext
|
||||
def make_elf(data, vma = None, strip=True, extract=True, shared=False):
|
||||
r"""
|
||||
Builds an ELF file with the specified binary data as its
|
||||
executable code.
|
||||
def make_elf(data,
|
||||
vma=None,
|
||||
strip=True,
|
||||
extract=True,
|
||||
shared=False):
|
||||
r"""make_elf(data, vma=None, strip=True, extract=True, shared=False, **kwargs) -> str
|
||||
|
||||
Builds an ELF file with the specified binary data as its executable code.
|
||||
|
||||
Arguments:
|
||||
data(str): Assembled code
|
||||
vma(int): Load address for the ELF file
|
||||
strip(bool): Strip the resulting ELF file. Only matters if ``extract=False``.
|
||||
(Default: ``True``)
|
||||
extract(bool): Extract the assembly from the ELF file.
|
||||
If ``False``, the path of the ELF file is returned.
|
||||
(Default: ``True``)
|
||||
shared(bool): Create a Dynamic Shared Object (DSO, i.e. a ``.so``)
|
||||
which can be loaded via ``dlopen`` or ``LD_PRELOAD``.
|
||||
|
||||
Examples:
|
||||
|
||||
This example creates an i386 ELF that just does
|
||||
execve('/bin/sh',...).
|
||||
|
||||
>>> context.clear()
|
||||
>>> context.arch = 'i386'
|
||||
>>> context.bits = 32
|
||||
>>> filename = tempfile.mktemp()
|
||||
>>> context.clear(arch='i386')
|
||||
>>> bin_sh = '6a68682f2f2f73682f62696e89e331c96a0b5899cd80'.decode('hex')
|
||||
>>> data = make_elf(bin_sh)
|
||||
>>> with open(filename,'wb+') as f:
|
||||
... f.write(data)
|
||||
... f.flush()
|
||||
>>> os.chmod(filename,0777)
|
||||
>>> filename = make_elf(bin_sh, extract=False)
|
||||
>>> p = process(filename)
|
||||
>>> p.sendline('echo Hello; exit')
|
||||
>>> p.recvline()
|
||||
@@ -499,38 +609,37 @@ def make_elf(data, vma = None, strip=True, extract=True, shared=False):
|
||||
|
||||
@LocalContext
|
||||
def asm(shellcode, vma = 0, extract = True, shared = False):
|
||||
r"""asm(code, vma = 0, extract = True, ...) -> str
|
||||
r"""asm(code, vma = 0, extract = True, shared = False, ...) -> str
|
||||
|
||||
Runs :func:`cpp` over a given shellcode and then assembles it into bytes.
|
||||
|
||||
To see which architectures or operating systems are supported,
|
||||
look in :mod:`pwnlib.contex`.
|
||||
|
||||
To support all these architecture, we bundle the GNU assembler
|
||||
and objcopy with pwntools.
|
||||
Assembling shellcode requires that the GNU assembler is installed
|
||||
for the target architecture.
|
||||
See :doc:`Installing Binutils </install/binutils>` for more information.
|
||||
|
||||
Arguments:
|
||||
shellcode(str): Assembler code to assemble.
|
||||
vma(int): Virtual memory address of the beginning of assembly
|
||||
extract(bool): Extract the raw assembly bytes from the assembled
|
||||
file. If ``False``, returns the path to an ELF file
|
||||
with the assembly embedded.
|
||||
|
||||
Kwargs:
|
||||
Any arguments/properties that can be set on ``context``
|
||||
shellcode(str): Assembler code to assemble.
|
||||
vma(int): Virtual memory address of the beginning of assembly
|
||||
extract(bool): Extract the raw assembly bytes from the assembled
|
||||
file. If :const:`False`, returns the path to an ELF file
|
||||
with the assembly embedded.
|
||||
shared(bool): Create a shared object.
|
||||
kwargs(dict): Any attributes on :data:`.context` can be set, e.g.set
|
||||
``arch='arm'``.
|
||||
|
||||
Examples:
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> asm("mov eax, SYS_select", arch = 'i386', os = 'freebsd')
|
||||
'\xb8]\x00\x00\x00'
|
||||
>>> asm("mov eax, SYS_select", arch = 'amd64', os = 'linux')
|
||||
'\xb8\x17\x00\x00\x00'
|
||||
>>> asm("mov rax, SYS_select", arch = 'amd64', os = 'linux')
|
||||
'H\xc7\xc0\x17\x00\x00\x00'
|
||||
>>> asm("mov r0, #SYS_select", arch = 'arm', os = 'linux', bits=32)
|
||||
'R\x00\xa0\xe3'
|
||||
>>> asm("mov eax, SYS_select", arch = 'i386', os = 'freebsd')
|
||||
'\xb8]\x00\x00\x00'
|
||||
>>> asm("mov eax, SYS_select", arch = 'amd64', os = 'linux')
|
||||
'\xb8\x17\x00\x00\x00'
|
||||
>>> asm("mov rax, SYS_select", arch = 'amd64', os = 'linux')
|
||||
'H\xc7\xc0\x17\x00\x00\x00'
|
||||
>>> asm("mov r0, #SYS_select", arch = 'arm', os = 'linux', bits=32)
|
||||
'R\x00\xa0\xe3'
|
||||
"""
|
||||
result = ''
|
||||
|
||||
@@ -562,11 +671,20 @@ def asm(shellcode, vma = 0, extract = True, shared = False):
|
||||
ldflags = ['-z', 'execstack', '-o', step3, step2]
|
||||
if vma:
|
||||
ldflags += ['--section-start=.shellcode=%#x' % vma,
|
||||
'--entry=%#x' % vma,
|
||||
'-z', 'max-page-size=4096',
|
||||
'-z', 'common-page-size=4096']
|
||||
'--entry=%#x' % vma]
|
||||
elif shared:
|
||||
ldflags += ['-shared', '-init=_start']
|
||||
|
||||
# In order to ensure that we generate ELF files with 4k pages,
|
||||
# and not e.g. 65KB pages (AArch64), force the page size.
|
||||
# This is a result of GNU Gold being silly.
|
||||
#
|
||||
# Introduced in commit dd58f409 without supporting evidence,
|
||||
# this shouldn't do anything except keep consistent page granularity
|
||||
# across architectures.
|
||||
ldflags += ['-z', 'max-page-size=4096',
|
||||
'-z', 'common-page-size=4096']
|
||||
|
||||
_run(linker + ldflags)
|
||||
|
||||
elif file(step2,'rb').read(4) == '\x7fELF':
|
||||
@@ -618,24 +736,21 @@ def disasm(data, vma = 0, byte = True, offset = True, instructions = True):
|
||||
|
||||
Examples:
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> print disasm('b85d000000'.decode('hex'), arch = 'i386')
|
||||
0: b8 5d 00 00 00 mov eax,0x5d
|
||||
>>> print disasm('b85d000000'.decode('hex'), arch = 'i386', byte = 0)
|
||||
0: mov eax,0x5d
|
||||
>>> print disasm('b85d000000'.decode('hex'), arch = 'i386', byte = 0, offset = 0)
|
||||
mov eax,0x5d
|
||||
>>> print disasm('b817000000'.decode('hex'), arch = 'amd64')
|
||||
0: b8 17 00 00 00 mov eax,0x17
|
||||
>>> print disasm('48c7c017000000'.decode('hex'), arch = 'amd64')
|
||||
0: 48 c7 c0 17 00 00 00 mov rax,0x17
|
||||
>>> print disasm('04001fe552009000'.decode('hex'), arch = 'arm')
|
||||
0: e51f0004 ldr r0, [pc, #-4] ; 0x4
|
||||
4: 00900052 addseq r0, r0, r2, asr r0
|
||||
>>> print disasm('4ff00500'.decode('hex'), arch = 'thumb', bits=32)
|
||||
0: f04f 0005 mov.w r0, #5
|
||||
>>>
|
||||
>>> print disasm('b85d000000'.decode('hex'), arch = 'i386')
|
||||
0: b8 5d 00 00 00 mov eax,0x5d
|
||||
>>> print disasm('b85d000000'.decode('hex'), arch = 'i386', byte = 0)
|
||||
0: mov eax,0x5d
|
||||
>>> print disasm('b85d000000'.decode('hex'), arch = 'i386', byte = 0, offset = 0)
|
||||
mov eax,0x5d
|
||||
>>> print disasm('b817000000'.decode('hex'), arch = 'amd64')
|
||||
0: b8 17 00 00 00 mov eax,0x17
|
||||
>>> print disasm('48c7c017000000'.decode('hex'), arch = 'amd64')
|
||||
0: 48 c7 c0 17 00 00 00 mov rax,0x17
|
||||
>>> print disasm('04001fe552009000'.decode('hex'), arch = 'arm')
|
||||
0: e51f0004 ldr r0, [pc, #-4] ; 0x4
|
||||
4: 00900052 addseq r0, r0, r2, asr r0
|
||||
>>> print disasm('4ff00500'.decode('hex'), arch = 'thumb', bits=32)
|
||||
0: f04f 0005 mov.w r0, #5
|
||||
"""
|
||||
result = ''
|
||||
|
||||
@@ -669,7 +784,7 @@ def disasm(data, vma = 0, byte = True, offset = True, instructions = True):
|
||||
|
||||
res = _run(objcopy + [step1, step2])
|
||||
|
||||
output0 = subprocess.check_output(objdump + [step2])
|
||||
output0 = _run(objdump + [step2])
|
||||
output1 = output0.split('<.text>:\n')
|
||||
|
||||
if len(output1) != 2:
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
Analogous to atexit, this module allows the programmer to register functions to
|
||||
be run if an unhandled exception occurs.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
import sys
|
||||
import threading
|
||||
import traceback
|
||||
|
||||
from .context import context
|
||||
from pwnlib.context import context
|
||||
|
||||
__all__ = ['register', 'unregister']
|
||||
|
||||
|
||||
+2
-1
@@ -7,12 +7,13 @@ this replacement module also defines :func:`unregister`.
|
||||
This module also fixes a the issue that exceptions raised by an exit handler is
|
||||
printed twice when the standard :mod:`atexit` is used.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
import sys
|
||||
import threading
|
||||
import traceback
|
||||
|
||||
from .context import context
|
||||
from pwnlib.context import context
|
||||
|
||||
__all__ = ['register', 'unregister']
|
||||
|
||||
|
||||
@@ -1 +1,22 @@
|
||||
# empty
|
||||
#!/usr/bin/env python2
|
||||
__all__ = [
|
||||
'asm',
|
||||
'checksec',
|
||||
'common',
|
||||
'constgrep',
|
||||
'cyclic',
|
||||
'debug',
|
||||
'disasm',
|
||||
'disablenx',
|
||||
'elfdiff',
|
||||
'elfpatch',
|
||||
'errno',
|
||||
'hex',
|
||||
'main',
|
||||
'phd',
|
||||
'pwnstrip',
|
||||
'scramble',
|
||||
'shellcraft',
|
||||
'unhex',
|
||||
'update'
|
||||
]
|
||||
@@ -1,13 +1,15 @@
|
||||
#!/usr/bin/env python2
|
||||
from __future__ import absolute_import
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
from pwn import *
|
||||
from pwnlib.commandline import common
|
||||
|
||||
from . import common
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description = 'Assemble shellcode into bytes'
|
||||
parser = common.parser_commands.add_parser(
|
||||
'asm',
|
||||
help = 'Assemble shellcode into bytes'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
@@ -91,10 +93,13 @@ parser.add_argument(
|
||||
action='store_true'
|
||||
)
|
||||
|
||||
def main():
|
||||
args = parser.parse_args()
|
||||
def main(args):
|
||||
tty = args.output.isatty()
|
||||
|
||||
if args.infile.isatty() and not args.lines:
|
||||
parser.print_usage()
|
||||
sys.exit(1)
|
||||
|
||||
data = '\n'.join(args.lines) or args.infile.read()
|
||||
output = asm(data.replace(';', '\n'))
|
||||
fmt = args.format or ('hex' if tty else 'raw')
|
||||
@@ -123,4 +128,5 @@ def main():
|
||||
if tty and fmt is not 'raw':
|
||||
args.output.write('\n')
|
||||
|
||||
if __name__ == '__main__': main()
|
||||
if __name__ == '__main__':
|
||||
pwnlib.commandline.common.main(__file__)
|
||||
@@ -1,16 +1,16 @@
|
||||
#!/usr/bin/env python2
|
||||
from __future__ import absolute_import
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
from pwn import *
|
||||
from pwnlib.commandline import common
|
||||
|
||||
from . import common
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description = 'Check binary security settings'
|
||||
parser = common.parser_commands.add_parser(
|
||||
'checksec',
|
||||
help = 'Check binary security settings'
|
||||
)
|
||||
|
||||
|
||||
parser.add_argument(
|
||||
'elf',
|
||||
nargs='*',
|
||||
@@ -26,8 +26,7 @@ parser.add_argument(
|
||||
help='File to check (for compatibility with checksec.sh)'
|
||||
)
|
||||
|
||||
def main():
|
||||
args = parser.parse_args()
|
||||
def main(args):
|
||||
files = args.elf or args.elf2 or []
|
||||
|
||||
if not files:
|
||||
@@ -37,4 +36,5 @@ def main():
|
||||
for f in files:
|
||||
e = ELF(f.name)
|
||||
|
||||
if __name__ == '__main__': main()
|
||||
if __name__ == '__main__':
|
||||
pwnlib.commandline.common.main(__file__)
|
||||
@@ -1,10 +1,10 @@
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
import pwnlib
|
||||
from pwnlib.context import context
|
||||
|
||||
pwnlib.log.console.stream = sys.stderr
|
||||
|
||||
choices = map(str, [16,32,64])
|
||||
choices += list(context.oses)
|
||||
choices += list(context.architectures)
|
||||
@@ -20,3 +20,13 @@ def context_arg(arg):
|
||||
try: context.endian = arg
|
||||
except Exception: pass
|
||||
return arg
|
||||
|
||||
parser = argparse.ArgumentParser(description='Pwntools Command-line Interface',
|
||||
prog='pwn')
|
||||
parser_commands = parser.add_subparsers(dest='command')
|
||||
|
||||
def main(file=sys.argv[0]):
|
||||
import pwnlib.commandline.main
|
||||
name = os.path.splitext(os.path.basename(file))[0]
|
||||
sys.argv.insert(1, name)
|
||||
pwnlib.commandline.main.main()
|
||||
@@ -1,14 +1,19 @@
|
||||
#!/usr/bin/env python2
|
||||
from __future__ import absolute_import
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
|
||||
from pwn import *
|
||||
from . import common
|
||||
import pwnlib
|
||||
pwnlib.args.free_form = False
|
||||
|
||||
p = argparse.ArgumentParser(
|
||||
description = "Looking up constants from header files.\n\nExample: constgrep -c freebsd -m ^PROT_ '3 + 4'",
|
||||
from pwn import *
|
||||
from pwnlib.commandline import common
|
||||
|
||||
p = common.parser_commands.add_parser(
|
||||
'constgrep',
|
||||
help = "Looking up constants from header files.\n\nExample: constgrep -c freebsd -m ^PROT_ '3 + 4'",
|
||||
formatter_class = argparse.RawDescriptionHelpFormatter,
|
||||
)
|
||||
|
||||
@@ -55,9 +60,7 @@ p.add_argument(
|
||||
help = 'The os/architecture/endianness/bits the shellcode will run in (default: linux/i386), choose from: %s' % common.choices,
|
||||
)
|
||||
|
||||
def main():
|
||||
args = p.parse_args()
|
||||
|
||||
def main(args):
|
||||
if args.exact:
|
||||
# This is the simple case
|
||||
print cpp(args.exact).strip()
|
||||
@@ -75,6 +78,7 @@ def main():
|
||||
else:
|
||||
matcher = re.compile(args.regex)
|
||||
|
||||
|
||||
# Evaluate the given constant
|
||||
if args.constant:
|
||||
try:
|
||||
@@ -134,4 +138,5 @@ def main():
|
||||
print
|
||||
print '(%s) == %s' % (' | '.join(k for v, k in good), args.constant)
|
||||
|
||||
if __name__ == '__main__': main()
|
||||
if __name__ == '__main__':
|
||||
pwnlib.commandline.common.main(__file__)
|
||||
@@ -1,14 +1,19 @@
|
||||
#!/usr/bin/env python2
|
||||
from __future__ import absolute_import
|
||||
|
||||
import argparse
|
||||
import string
|
||||
import sys
|
||||
|
||||
import pwnlib
|
||||
pwnlib.args.free_form = False
|
||||
|
||||
from pwn import *
|
||||
from pwnlib.commandline import common
|
||||
|
||||
from . import common
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description = "Cyclic pattern creator/finder"
|
||||
parser = common.parser_commands.add_parser(
|
||||
'cyclic',
|
||||
help = "Cyclic pattern creator/finder"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
@@ -50,8 +55,7 @@ group.add_argument(
|
||||
help = 'Number of characters to print'
|
||||
)
|
||||
|
||||
def main():
|
||||
args = parser.parse_args()
|
||||
def main(args):
|
||||
alphabet = args.alphabet
|
||||
subsize = args.length
|
||||
|
||||
@@ -90,4 +94,5 @@ def main():
|
||||
if sys.stdout.isatty():
|
||||
sys.stdout.write('\n')
|
||||
|
||||
if __name__ == '__main__': main()
|
||||
if __name__ == '__main__':
|
||||
pwnlib.commandline.common.main(__file__)
|
||||
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env python2
|
||||
from __future__ import absolute_import
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
from pwn import *
|
||||
from pwnlib.commandline import common
|
||||
|
||||
parser = common.parser_commands.add_parser(
|
||||
'debug',
|
||||
help = 'Debug a binary in GDB'
|
||||
)
|
||||
parser.add_argument(
|
||||
'-x', metavar='GDBSCRIPT',
|
||||
type=file,
|
||||
help='Execute GDB commands from this file.'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--pid',
|
||||
type=int,
|
||||
help="PID to attach to"
|
||||
)
|
||||
parser.add_argument(
|
||||
'-c', '--context',
|
||||
metavar = 'context',
|
||||
action = 'append',
|
||||
type = common.context_arg,
|
||||
choices = common.choices,
|
||||
help = 'The os/architecture/endianness/bits the shellcode will run in (default: linux/i386), choose from: %s' % common.choices,
|
||||
)
|
||||
parser.add_argument(
|
||||
'--exec',
|
||||
|
||||
# NOTE: Type cannot be "file" because we may be referring to a remote
|
||||
# file, or a file on an Android device.
|
||||
type=str,
|
||||
|
||||
dest='executable',
|
||||
help='File to debug'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--process', metavar='PROCESS_NAME',
|
||||
help='Name of the process to attach to (e.g. "bash")'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--sysroot', metavar='SYSROOT',
|
||||
type=str,
|
||||
default='',
|
||||
help="GDB sysroot path"
|
||||
)
|
||||
|
||||
def main(args):
|
||||
gdbscript = ''
|
||||
if args.x:
|
||||
gdbscript = args.x.read()
|
||||
|
||||
if context.os == 'android':
|
||||
context.device = adb.wait_for_device()
|
||||
|
||||
if args.executable:
|
||||
if os.path.exists(args.executable):
|
||||
context.binary = ELF(args.executable)
|
||||
target = context.binary.path
|
||||
|
||||
# This path does nothing, but avoids the "print_usage()"
|
||||
# path below.
|
||||
elif context.os == 'android':
|
||||
target = args.executable
|
||||
elif args.pid:
|
||||
target = int(args.pid)
|
||||
elif args.process:
|
||||
if context.os == 'android':
|
||||
target = adb.pidof(args.process)
|
||||
else:
|
||||
target = pidof(args.process)
|
||||
|
||||
# pidof() returns a list
|
||||
if not target:
|
||||
log.error("Could not find a PID for %r", args.process)
|
||||
target = target[0]
|
||||
else:
|
||||
parser.print_usage()
|
||||
return 1
|
||||
|
||||
if args.pid or args.process:
|
||||
pid = gdb.attach(target, gdbscript=gdbscript, sysroot=args.sysroot)
|
||||
|
||||
# Since we spawned the gdbserver process, and process registers an
|
||||
# atexit handler to close itself, gdbserver will be terminated when
|
||||
# we exit. This will manifest as a "remote connected ended" or
|
||||
# similar error message. Hold it open for the user.
|
||||
log.info("GDB connection forwarding will terminate when you press enter")
|
||||
pause()
|
||||
else:
|
||||
gdb.debug(target, gdbscript=gdbscript, sysroot=args.sysroot).interactive()
|
||||
|
||||
if __name__ == '__main__':
|
||||
pwnlib.commandline.common.main(__file__)
|
||||
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env python2
|
||||
from __future__ import absolute_import
|
||||
|
||||
from pwn import *
|
||||
from pwnlib.commandline import common
|
||||
|
||||
parser = common.parser_commands.add_parser(
|
||||
'disablenx',
|
||||
help = 'Disable NX for an ELF binary'
|
||||
)
|
||||
parser.add_argument(
|
||||
'elf',
|
||||
nargs='+',
|
||||
type=file,
|
||||
help='Files to check'
|
||||
)
|
||||
|
||||
def main(args):
|
||||
for f in args.elf:
|
||||
e = ELF(f.name)
|
||||
e.disable_nx()
|
||||
ELF(e.path)
|
||||
|
||||
if __name__ == '__main__':
|
||||
pwnlib.commandline.common.main(__file__)
|
||||
@@ -1,14 +1,19 @@
|
||||
#!/usr/bin/env python2
|
||||
from __future__ import absolute_import
|
||||
|
||||
import argparse
|
||||
import string
|
||||
import sys
|
||||
|
||||
import pwnlib
|
||||
pwnlib.args.free_form = False
|
||||
|
||||
from pwn import *
|
||||
from pwnlib.commandline import common
|
||||
|
||||
from . import common
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description = 'Disassemble bytes into text format'
|
||||
parser = common.parser_commands.add_parser(
|
||||
'disasm',
|
||||
help = 'Disassemble bytes into text format'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
@@ -52,9 +57,7 @@ parser.add_argument(
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
args = parser.parse_args()
|
||||
|
||||
def main(args):
|
||||
if len(args.hex) > 0:
|
||||
dat = ''.join(args.hex)
|
||||
dat = dat.translate(None, string.whitespace)
|
||||
@@ -88,4 +91,5 @@ def main():
|
||||
|
||||
print disasm(dat, vma=safeeval.const(args.address))
|
||||
|
||||
if __name__ == '__main__': main()
|
||||
if __name__ == '__main__':
|
||||
pwnlib.commandline.common.main(__file__)
|
||||
@@ -1,12 +1,18 @@
|
||||
#!/usr/bin/env python2
|
||||
import shutil
|
||||
from __future__ import absolute_import
|
||||
|
||||
import shutil
|
||||
from argparse import ArgumentParser
|
||||
from subprocess import CalledProcessError
|
||||
from subprocess import check_output
|
||||
from tempfile import NamedTemporaryFile
|
||||
|
||||
import pwnlib
|
||||
pwnlib.args.free_form = False
|
||||
|
||||
from pwn import *
|
||||
from pwnlib.commandline import common
|
||||
|
||||
|
||||
def dump(objdump, path):
|
||||
n = NamedTemporaryFile(delete=False)
|
||||
@@ -20,13 +26,15 @@ def diff(a,b):
|
||||
except CalledProcessError as e:
|
||||
return e.output
|
||||
|
||||
p = ArgumentParser()
|
||||
p = common.parser_commands.add_parser(
|
||||
'elfdiff',
|
||||
help = 'Compare two ELF files'
|
||||
)
|
||||
|
||||
p.add_argument('a')
|
||||
p.add_argument('b')
|
||||
|
||||
def main():
|
||||
a = p.parse_args()
|
||||
|
||||
def main(a):
|
||||
with context.silent:
|
||||
x = ELF(a.a)
|
||||
y = ELF(a.b)
|
||||
@@ -49,4 +57,5 @@ def main():
|
||||
|
||||
print diff(x, y)
|
||||
|
||||
if __name__ == '__main__': main()
|
||||
if __name__ == '__main__':
|
||||
pwnlib.commandline.common.main(__file__)
|
||||
@@ -1,8 +1,19 @@
|
||||
#!/usr/bin/env python2
|
||||
from __future__ import absolute_import
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
import pwnlib
|
||||
pwnlib.args.free_form = False
|
||||
|
||||
from pwn import *
|
||||
from pwnlib.commandline import common
|
||||
|
||||
p = common.parser_commands.add_parser(
|
||||
'elfpatch',
|
||||
help = 'Patch an ELF file'
|
||||
)
|
||||
|
||||
p = argparse.ArgumentParser()
|
||||
p.add_argument('elf',help="File to patch")
|
||||
@@ -10,9 +21,7 @@ p.add_argument('offset',help="Offset to patch in virtual address (hex encoded)")
|
||||
p.add_argument('bytes',help='Bytes to patch (hex encoded)')
|
||||
|
||||
|
||||
def main():
|
||||
a = p.parse_args()
|
||||
|
||||
def main(a):
|
||||
if not a.offset.startswith('0x'):
|
||||
a.offset = '0x' + a.offset
|
||||
|
||||
@@ -25,4 +34,5 @@ def main():
|
||||
elf.write(offset, bytes)
|
||||
sys.stdout.write(elf.get_data())
|
||||
|
||||
if __name__ == '__main__': main()
|
||||
if __name__ == '__main__':
|
||||
pwnlib.commandline.common.main(__file__)
|
||||
@@ -1,17 +1,20 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
import argparse
|
||||
import os
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description = 'Prints out error messages'
|
||||
from pwnlib.commandline import common
|
||||
|
||||
parser = common.parser_commands.add_parser(
|
||||
'errno',
|
||||
help = 'Prints out error messages'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'error', help='Error message or value', type=str
|
||||
)
|
||||
|
||||
def main():
|
||||
args, unknown = parser.parse_known_args()
|
||||
|
||||
def main(args):
|
||||
try:
|
||||
value = int(args.error, 0)
|
||||
|
||||
@@ -40,4 +43,5 @@ def main():
|
||||
print '#define', name, value
|
||||
print os.strerror(value)
|
||||
|
||||
if __name__ == '__main__': main()
|
||||
if __name__ == '__main__':
|
||||
pwnlib.commandline.common.main(__file__)
|
||||
@@ -1,18 +1,24 @@
|
||||
#!/usr/bin/env python2
|
||||
from __future__ import absolute_import
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
parser = argparse.ArgumentParser(description='''
|
||||
Hex-encodes data provided on the command line or via stdin.
|
||||
from pwnlib.commandline import common
|
||||
|
||||
parser = common.parser_commands.add_parser(
|
||||
'hex',
|
||||
help = '''
|
||||
Hex-encodes data provided on the command line or stdin
|
||||
''')
|
||||
parser.add_argument('data', nargs='*',
|
||||
help='Data to convert into hex')
|
||||
|
||||
def main():
|
||||
args = parser.parse_args()
|
||||
def main(args):
|
||||
if not args.data:
|
||||
print sys.stdin.read().encode('hex')
|
||||
else:
|
||||
print ' '.join(args.data).encode('hex')
|
||||
|
||||
if __name__ == '__main__': main()
|
||||
if __name__ == '__main__':
|
||||
pwnlib.commandline.common.main(__file__)
|
||||
@@ -0,0 +1,54 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
import sys
|
||||
|
||||
from pwnlib.commandline import asm
|
||||
from pwnlib.commandline import checksec
|
||||
from pwnlib.commandline import common
|
||||
from pwnlib.commandline import constgrep
|
||||
from pwnlib.commandline import cyclic
|
||||
from pwnlib.commandline import debug
|
||||
from pwnlib.commandline import disasm
|
||||
from pwnlib.commandline import disablenx
|
||||
from pwnlib.commandline import elfdiff
|
||||
from pwnlib.commandline import elfpatch
|
||||
from pwnlib.commandline import errno
|
||||
from pwnlib.commandline import hex
|
||||
from pwnlib.commandline import phd
|
||||
from pwnlib.commandline import pwnstrip
|
||||
from pwnlib.commandline import scramble
|
||||
from pwnlib.commandline import shellcraft
|
||||
from pwnlib.commandline import template
|
||||
from pwnlib.commandline import unhex
|
||||
from pwnlib.commandline import update
|
||||
from pwnlib.commandline.common import parser
|
||||
from pwnlib.context import context
|
||||
|
||||
commands = {
|
||||
'asm': asm.main,
|
||||
'checksec': checksec.main,
|
||||
'constgrep': constgrep.main,
|
||||
'cyclic': cyclic.main,
|
||||
'debug': debug.main,
|
||||
'disasm': disasm.main,
|
||||
'disablenx': disablenx.main,
|
||||
'elfdiff': elfdiff.main,
|
||||
'elfpatch': elfpatch.main,
|
||||
'errno': errno.main,
|
||||
'hex': hex.main,
|
||||
'phd': phd.main,
|
||||
'pwnstrip': pwnstrip.main,
|
||||
'scramble': scramble.main,
|
||||
'shellcraft': shellcraft.main,
|
||||
'template': template.main,
|
||||
'unhex': unhex.main,
|
||||
'update': update.main,
|
||||
}
|
||||
|
||||
def main():
|
||||
args = parser.parse_args()
|
||||
with context.local(log_console = sys.stderr):
|
||||
commands[args.command](args)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
+14
-10
@@ -1,12 +1,19 @@
|
||||
#!/usr/bin/env python2
|
||||
from __future__ import absolute_import
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
from pwn import *
|
||||
import pwnlib
|
||||
pwnlib.args.free_form = False
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description = 'Pwnlib HexDump'
|
||||
from pwn import *
|
||||
from pwnlib.commandline import common
|
||||
|
||||
parser = common.parser_commands.add_parser(
|
||||
'phd',
|
||||
help = 'Pwnlib HexDump'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
@@ -64,9 +71,7 @@ def asint(s):
|
||||
else:
|
||||
return int(s, 10)
|
||||
|
||||
def main():
|
||||
args = parser.parse_args()
|
||||
|
||||
def main(args):
|
||||
infile = args.file
|
||||
width = asint(args.width)
|
||||
skip = asint(args.skip)
|
||||
@@ -83,8 +88,6 @@ def main():
|
||||
else:
|
||||
infile.seek(skip, os.SEEK_CUR)
|
||||
|
||||
data = infile.read(count)
|
||||
|
||||
hl = []
|
||||
if args.highlight:
|
||||
for hs in args.highlight:
|
||||
@@ -92,9 +95,10 @@ def main():
|
||||
hl.append(asint(h))
|
||||
|
||||
try:
|
||||
for line in hexdump_iter(data, width, highlight = hl, begin = offset + skip):
|
||||
for line in hexdump_iter(infile, width, highlight = hl, begin = offset + skip):
|
||||
print line
|
||||
except (KeyboardInterrupt, IOError):
|
||||
pass
|
||||
|
||||
if __name__ == '__main__': main()
|
||||
if __name__ == '__main__':
|
||||
pwnlib.commandline.common.main(__file__)
|
||||
@@ -1,12 +1,16 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
import argparse
|
||||
|
||||
import pwnlib
|
||||
pwnlib.args.free_form = False
|
||||
|
||||
from pwn import *
|
||||
from pwnlib.commandline import common
|
||||
|
||||
from . import common
|
||||
|
||||
p = argparse.ArgumentParser(
|
||||
description = 'Strip binaries for CTF usage',
|
||||
formatter_class = argparse.RawDescriptionHelpFormatter,
|
||||
p = common.parser_commands.add_parser(
|
||||
'pwnstrip',
|
||||
help = 'Strip binaries for CTF usage',
|
||||
)
|
||||
|
||||
g = p.add_argument_group("actions")
|
||||
@@ -15,9 +19,7 @@ g.add_argument('-p', '--patch', metavar='FUNCTION', help="Patch function", actio
|
||||
p.add_argument('-o', '--output', type=file, default=sys.stdout)
|
||||
p.add_argument('file', type=file)
|
||||
|
||||
def main():
|
||||
args = p.parse_args()
|
||||
|
||||
def main(args):
|
||||
if not (args.patch or args.build_id):
|
||||
sys.stderr.write("Must specify at least one action\n")
|
||||
sys.stderr.write(p.format_usage())
|
||||
@@ -48,6 +50,5 @@ def main():
|
||||
|
||||
args.output.write(result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
pwnlib.commandline.common.main(__file__)
|
||||
@@ -1,15 +1,19 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
import pwnlib
|
||||
pwnlib.args.free_form = False
|
||||
|
||||
from pwn import *
|
||||
from pwnlib.commandline import common
|
||||
|
||||
from . import common
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description = 'Shellcode encoder'
|
||||
parser = common.parser_commands.add_parser(
|
||||
'scramble',
|
||||
help = 'Shellcode encoder'
|
||||
)
|
||||
|
||||
|
||||
parser.add_argument(
|
||||
"-f", "--format",
|
||||
help="Output format (defaults to hex for ttys, otherwise raw)",
|
||||
@@ -68,8 +72,7 @@ parser.add_argument(
|
||||
action='store_true'
|
||||
)
|
||||
|
||||
def main():
|
||||
args = parser.parse_args()
|
||||
def main(args):
|
||||
tty = args.output.isatty()
|
||||
|
||||
if sys.stdin.isatty():
|
||||
@@ -100,4 +103,6 @@ def main():
|
||||
if tty and fmt is not 'raw':
|
||||
args.output.write('\n')
|
||||
|
||||
if __name__ == '__main__': main()
|
||||
|
||||
if __name__ == '__main__':
|
||||
pwnlib.commandline.common.main(__file__)
|
||||
@@ -1,24 +1,16 @@
|
||||
#!/usr/bin/env python2
|
||||
from __future__ import absolute_import
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import types
|
||||
|
||||
import pwnlib
|
||||
pwnlib.args.free_form = False
|
||||
|
||||
from pwn import *
|
||||
|
||||
from . import common
|
||||
|
||||
r = text.red
|
||||
g = text.green
|
||||
b = text.blue
|
||||
|
||||
banner = '\n'.join([' ' + r('____') + ' ' + g('_') + ' ' + r('_') + ' ' + g('_') + ' ' + b('__') + ' ' + r('_'),
|
||||
' ' + r('/ ___|') + g('| |__') + ' ' + b('___') + r('| |') + ' ' + g('|') + ' ' + b('___') + ' ' + r('_ __') + ' ' + g('__ _') + ' ' + b('/ _|') + ' ' + r('|_'),
|
||||
' ' + r('\___ \\') + g('| \'_ \\') + ' ' + b('/ _ \\') + ' ' + r('|') + ' ' + g('|') + b('/ __|') + ' ' + r('\'__/') + ' ' + g('_` |') + ' ' + b('|_') + r('| __|'),
|
||||
' ' + r('___) |') + ' ' + g('| | |') + ' ' + b('__/') + ' ' + r('|') + ' ' + g('|') + ' ' + b('(__') + r('| |') + ' ' + g('| (_| |') + ' ' + b('_|') + ' ' + r('|_'),
|
||||
' ' + r('|____/') + g('|_| |_|') + b('\\___|') + r('_|') + g('_|') + b('\\___|') + r('_|') + ' ' + g('\\__,_|') + b('_|') + ' ' + r('\\__|'),
|
||||
'\n'
|
||||
])
|
||||
from pwnlib.commandline import common
|
||||
|
||||
|
||||
# ____ _ _ _ __ _
|
||||
@@ -37,9 +29,10 @@ def _string(s):
|
||||
out.append('\\x%02x' % co)
|
||||
return '"' + ''.join(out) + '"\n'
|
||||
|
||||
p = argparse.ArgumentParser(
|
||||
description = 'Microwave shellcode -- Easy, fast and delicious',
|
||||
formatter_class = argparse.RawDescriptionHelpFormatter,
|
||||
|
||||
p = common.parser_commands.add_parser(
|
||||
'shellcraft',
|
||||
help = 'Microwave shellcode -- Easy, fast and delicious',
|
||||
)
|
||||
|
||||
|
||||
@@ -68,21 +61,19 @@ p.add_argument(
|
||||
'p',
|
||||
'i', 'hexii',
|
||||
'e', 'elf',
|
||||
'd', 'escaped',
|
||||
'default'],
|
||||
default = 'default',
|
||||
help = 'Output format (default: hex), choose from {r}aw, {s}tring, {c}-style array, {h}ex string, hex{i}i, {a}ssembly code, {p}reprocssed code',
|
||||
help = 'Output format (default: hex), choose from {e}lf, {r}aw, {s}tring, {c}-style array, {h}ex string, hex{i}i, {a}ssembly code, {p}reprocssed code, escape{d} hex string',
|
||||
)
|
||||
|
||||
p.add_argument(
|
||||
'shellcode',
|
||||
nargs = '?',
|
||||
choices = shellcraft.templates,
|
||||
metavar = 'shellcode',
|
||||
help = 'The shellcode you want',
|
||||
type = str
|
||||
)
|
||||
|
||||
p.epilog = 'Available shellcodes are:\n' + '\n'.join(shellcraft.templates)
|
||||
|
||||
p.add_argument(
|
||||
'args',
|
||||
nargs = '*',
|
||||
@@ -167,6 +158,18 @@ p.add_argument(
|
||||
default=None
|
||||
)
|
||||
|
||||
p.add_argument(
|
||||
'-l', '--list',
|
||||
action='store_true',
|
||||
help='List available shellcodes, optionally provide a filter'
|
||||
)
|
||||
|
||||
p.add_argument(
|
||||
'-s', '--shared',
|
||||
action='store_true',
|
||||
help='Generated ELF is a shared library'
|
||||
)
|
||||
|
||||
def get_template(name):
|
||||
func = shellcraft
|
||||
for attr in name.split('.'):
|
||||
@@ -175,23 +178,27 @@ def get_template(name):
|
||||
|
||||
def is_not_a_syscall_template(name):
|
||||
template_src = shellcraft._get_source(name)
|
||||
return 'man 2' not in read(template_src)
|
||||
return '/syscalls' not in template_src
|
||||
|
||||
def main():
|
||||
# Banner must be added here so that it doesn't appear in the autodoc
|
||||
# generation for command line tools
|
||||
p.description = banner + p.description
|
||||
args = p.parse_args()
|
||||
|
||||
if not args.shellcode:
|
||||
def main(args):
|
||||
if args.list:
|
||||
templates = shellcraft.templates
|
||||
|
||||
if not args.syscalls:
|
||||
if args.shellcode:
|
||||
templates = filter(lambda a: args.shellcode in a, templates)
|
||||
elif not args.syscalls:
|
||||
templates = filter(is_not_a_syscall_template, templates)
|
||||
|
||||
print '\n'.join(templates)
|
||||
exit()
|
||||
|
||||
if not args.shellcode:
|
||||
common.parser.print_usage()
|
||||
exit()
|
||||
|
||||
if args.shellcode not in shellcraft.templates:
|
||||
log.error("Unknown shellcraft template %r. Use --list to see available shellcodes." % args.shellcode)
|
||||
|
||||
func = get_template(args.shellcode)
|
||||
|
||||
if args.show:
|
||||
@@ -295,11 +302,11 @@ def main():
|
||||
|
||||
|
||||
if not args.avoid:
|
||||
code = read(make_elf_from_assembly(assembly, vma=vma))
|
||||
code = read(make_elf_from_assembly(assembly, vma=vma, shared=args.shared))
|
||||
else:
|
||||
code = asm(assembly)
|
||||
code = encode(code, args.avoid)
|
||||
code = make_elf(code, vma=vma)
|
||||
code = make_elf(code, vma=vma, shared=args.shared)
|
||||
# code = read(make_elf(encode(asm(code), args.avoid)))
|
||||
else:
|
||||
code = encode(asm(assembly), args.avoid)
|
||||
@@ -326,17 +333,19 @@ def main():
|
||||
sys.exit(0)
|
||||
|
||||
if args.format in ['s', 'str', 'string']:
|
||||
code = _string(code) + '"\n'
|
||||
code = _string(code)
|
||||
elif args.format == 'c':
|
||||
code = '{' + ', '.join(map(hex, bytearray(code))) + '}' + '\n'
|
||||
elif args.format in ['h', 'hex']:
|
||||
code = pwnlib.util.fiddling.enhex(code) + '\n'
|
||||
elif args.format in ['i', 'hexii']:
|
||||
code = hexii(code) + '\n'
|
||||
|
||||
elif args.format in ['d', 'escaped']:
|
||||
code = ''.join('\\x%02x' % ord(c) for c in code) + '\n'
|
||||
if not sys.stdin.isatty():
|
||||
args.out.write(sys.stdin.read())
|
||||
|
||||
args.out.write(code)
|
||||
|
||||
if __name__ == '__main__': main()
|
||||
if __name__ == '__main__':
|
||||
pwnlib.commandline.common.main(__file__)
|
||||
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python2
|
||||
from __future__ import absolute_import
|
||||
|
||||
import re
|
||||
|
||||
from pwn import *
|
||||
from pwnlib.commandline import common
|
||||
|
||||
from mako.lookup import TemplateLookup
|
||||
|
||||
parser = common.parser_commands.add_parser(
|
||||
'template',
|
||||
help = 'Generate an exploit template'
|
||||
)
|
||||
|
||||
parser.add_argument('exe', nargs='?', help='Target binary')
|
||||
parser.add_argument('--host', help='Remote host / SSH server')
|
||||
parser.add_argument('--port', help='Remote port / SSH port', type=int)
|
||||
parser.add_argument('--user', help='SSH Username')
|
||||
parser.add_argument('--pass', help='SSH Password', dest='password')
|
||||
parser.add_argument('--path', help='Remote path of file on SSH server')
|
||||
parser.add_argument('--quiet', help='Less verbose template comments', action='store_true')
|
||||
|
||||
def main(args):
|
||||
cache = None
|
||||
|
||||
if cache:
|
||||
cache = os.path.join(context.cache_dir, 'mako')
|
||||
|
||||
lookup = TemplateLookup(
|
||||
directories = [os.path.join(pwnlib.data.path, 'templates')],
|
||||
module_directory = cache
|
||||
)
|
||||
|
||||
# For the SSH scenario, check that the binary is at the
|
||||
# same path on the remote host.
|
||||
if args.user:
|
||||
if not (args.path or args.exe):
|
||||
log.error("Must specify --path or a exe")
|
||||
|
||||
s = ssh(args.user, args.host, args.port or 22, args.password or None)
|
||||
s.download(args.path or args.exe)
|
||||
|
||||
if not args.exe:
|
||||
args.exe = os.path.basename(args.path)
|
||||
|
||||
template = lookup.get_template('pwnup.mako')
|
||||
output = template.render(args.exe,
|
||||
args.host,
|
||||
args.port,
|
||||
args.user,
|
||||
args.password,
|
||||
args.path,
|
||||
args.quiet)
|
||||
|
||||
# Fix Mako formatting bs
|
||||
output = re.sub('\n\n\n', '\n\n', output)
|
||||
|
||||
print output
|
||||
|
||||
if not sys.stdout.isatty():
|
||||
try: os.fchmod(sys.stdout.fileno(), 0700)
|
||||
except OSError: pass
|
||||
|
||||
if __name__ == '__main__':
|
||||
pwnlib.commandline.common.main(__file__)
|
||||
@@ -1,23 +1,30 @@
|
||||
#!/usr/bin/env python2
|
||||
from __future__ import absolute_import
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from string import whitespace
|
||||
|
||||
parser = argparse.ArgumentParser(description='''
|
||||
from pwnlib.commandline import common
|
||||
|
||||
parser = common.parser_commands.add_parser(
|
||||
'unhex',
|
||||
help = '''
|
||||
Decodes hex-encoded data provided on the command line or via stdin.
|
||||
''')
|
||||
|
||||
parser.add_argument('hex', nargs='*',
|
||||
help='Hex bytes to decode')
|
||||
|
||||
def main():
|
||||
args = parser.parse_args()
|
||||
def main(args):
|
||||
try:
|
||||
if not args.hex:
|
||||
s = sys.stdin.read().translate(None, whitespace)
|
||||
sys.stdout.write(s.decode('hex'))
|
||||
else:
|
||||
sys.stdout.write(''.join(sys.argv[1:]).decode('hex'))
|
||||
sys.stdout.write(''.join(args.hex).decode('hex'))
|
||||
except TypeError, e:
|
||||
sys.stderr.write(str(e) + '\n')
|
||||
|
||||
if __name__ == '__main__': main()
|
||||
if __name__ == '__main__':
|
||||
pwnlib.commandline.common.main(__file__)
|
||||
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env python2
|
||||
from __future__ import absolute_import
|
||||
|
||||
import subprocess
|
||||
|
||||
import pwnlib
|
||||
pwnlib.args.free_form = False
|
||||
|
||||
from pwn import *
|
||||
from pwnlib.commandline import common
|
||||
|
||||
p = common.parser_commands.add_parser(
|
||||
'update',
|
||||
help = 'Check for pwntools updates'
|
||||
)
|
||||
|
||||
p.add_argument('--install', action='store_true', help='''
|
||||
Install the update automatically.
|
||||
''')
|
||||
|
||||
p.add_argument('--pre', action='store_true', help='''
|
||||
Check for pre-releases.
|
||||
''')
|
||||
|
||||
def main(a):
|
||||
result = pwnlib.update.perform_check(prerelease=a.pre)
|
||||
if a.install:
|
||||
subprocess.check_call(result, shell=False)
|
||||
|
||||
if __name__ == '__main__':
|
||||
pwnlib.commandline.common.main(__file__)
|
||||
Loaded 100 of 3692 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user