This file is indexed.

/usr/share/doc/radare-doc/html/Section22.3.1.html is in radare-doc 1:1.5.2-6.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
904
905
906
907
908
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=US-ASCII">
<title>Solution</title>
<link rel="previous" href="Section22.3.html">
<link rel="ToC" href="contents.html">
<link rel="next" href="Section22.4.html">
</head>
<body>
<h1><a name="pcme0-solution"></a>22.3.1 Solution</h1>
<p>
Solution to pcme0 solution, description by: rookie (wo_gue@gmx.de).
</p>
<p>
Tools used: radare, linux standard tools.
</p>
<p>
Steps to solve: Check filetype:
</p>
<pre><code>&gt; file pcme0
pcme0: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV),
 for GNU/Linux 2.4.1, dynamically linked (uses shared libs), stripped
</code></pre>
<p>
at least shared. So library calls can be identified.
</p>
<p>
Running pcme0 shows a couple of strings,
</p>
<pre><code>$ ./pcme0
[pancrackme] v1.0
Password: 123
oops
</code></pre>
<p>
which can be searched in the executable.
</p>
<pre><code>$ strings ./pcme0 | grep -i "pancrackme\|Password\|oops"
[pancrackme] v1.0
Password:
</code></pre>
<p>
no luck finding "oops". Could have been a good hint, where to find a bad-boy ("oops") exit.
</p>
<p>
Running ltrace to see what pcme0 does (with -i so we can later on compare addresses with the disassembly):
</p>
<pre><code>$ ltrace -i ./pcme0
...
[0x8048791] __libc_start_main(0x8048ed6, 1, 0xbfb798f4, 0x8049060, 0x8049050 
[0x8048f06] getppid()                                                = 3571
[0x8048f36] printf("[pancrackme] v1.0\n"[pancrackme] v1.0
)                            = 18
[0x8048f57] mprotect(0x8048000, 1264, 7, 0x8048f06, 0xb7f63369)      = 0
[0x8048fa0] getpid()                                                 = 3572
[0x8048faf] random()                                                 = 1804289383
[0x8048ff3] rand(0xb7f63369, 0xb7e82f55, 0xbfb79868, 0x8048ee4, 0xb7f9dff4) = 0x327b23c6
[0x8048e21] getppid()                                                = 3571
[0x8048e38] sprintf("/proc/3571/cmdline", "/proc/%d/cmdline", 3571)  = 18
[0x8048e4c] open("/proc/3571/cmdline", 0, 06763)                     = 3
[0x8048e78] read(3, "ltrace", 100)                                   = 18
[0x8048ebf] close(3)                                                 = 0
[0x8048a00] getpid()                                                 = 3572
[0x8048a20] signal(14, 0x80488f1)                                    = NULL
[0x8048a32] pipe(0x804a300)                                          = 0
[0x8048a45] dup2(0, 3)                                               = 3
[0x8048a4d] rand(0x80489e6, 0x80489e6, 0x80489e6, 0x80489e6, 3572)   = 0x643c9869
[0x8048a8d] fork()                                                   = 3573
[0x8048aab] signal(10, 0x80488e7)                                    = NULL
[0x8048abf] signal(2, 0x80489ab)                                     = NULL
[0x8048ae1] write(1, "Password: ", 10Password: )                               = 10
[0x8048ae9] pause(0x80489e6, 0x80489e6, 0x80489e6, 5, 3572123
oops
</code></pre>
<pre><code>[0xffffe410] --- SIGUSR1 (User defined signal 1) ---
[0x80488e7] --- SIGCHLD (Child exited) ---
[0xffffffff] +++ exited (status 64) +++
</code></pre>
<p>
interesting parts: Seems like comandline is analyzed for some reason.
</p>
<pre><code>[0x8048e4c] open("/proc/3571/cmdline", 0, 06763)                     = 3
[0x8048e78] read(3, "ltrace", 100)                                   = 18
[0x8048ebf] close(3)                                                 = 0
</code></pre>
<p>
A couple of user defined signals are set up:
</p>
<pre><code>[0x8048a20] signal(14, 0x80488f1)                                    = NULL
.
[0x8048aab] signal(10, 0x80488e7)                                    = NULL
.
[0x8048abf] signal(2, 0x80489ab)                                     = NULL
</code></pre>
<p>
Looks like the process forks and
</p>
<pre><code>[0x8048a8d] fork()
</code></pre>
<p>
user input is not read in the parent process.
</p>
<p>
Running ltrace again with follow forking option:
</p>
<pre><code>&gt; ltrace -if ./pcme0
.
[0x8048a8d] fork(Cannot attach to pid 3589: Operation not permitted
</code></pre>
<p>
Looks like process is already traced. Time to disassemble the binary, using one of radare's tools 'rsc', with script 'bin2txt'.
</p>
<pre><code>&gt; rsc bin2txt ./pcme0 &gt; pcme0_1.s
</code></pre>
<p>
Searching for a ptrace call in disassembly shows two occurences:
</p>
<pre><code>_08048b61:  e8 46 fb ff ff          call   _080486ac 
</code></pre>
<p>
and
</p>
<pre><code>_08048cad:  e8 fa f9 ff ff          call   _080486ac 
</code></pre>
<p>
so why not replace them with "nop", but make sure the return value is 0. Starting radare to edit the binary to replace the ptrace calls:
</p>
<pre><code>&gt; cp pcme0 pcme0_patched1
&gt;  radare -cw ./pcme0_patched1
warning: Opening file in read-write mode
open rw ./pcme0_patched1
[0x00000000]&gt;
[0x00000000]&gt; s 0xb61
0x00000B61
[0x00000B61]&gt; wx 31 c0 90 90 90
[0x00000B61]&gt; pD 20
0x00000B61 31c0                      eax ^= eax
0x00000B63 90                        nop
0x00000B64 90                        nop
0x00000B65 90                        nop
0x00000B66 83c410                    esp += 0x10  ; 16
0x00000B69 8983a80000                invalid
[0x00000B61]&gt; q
</code></pre>
<p>
same for call at _08048cad....
</p>
<p>
Running patched pcme0 using strace with follow fork:
</p>
<pre><code>&gt; strace -if ./pcme0_patched1
.
[ffffe410] clone(Process 4209 attached
child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb7e486f8) = 4209
[pid  4208] [ffffe410] rt_sigaction(SIGUSR1, {0x80488e7, [USR1], SA_RESTART}, {SIG_DFL}, 8) = 0
[pid  4208] [ffffe410] rt_sigaction(SIGINT, {0x80489ab, [INT], SA_RESTART}, {SIG_DFL}, 8) = 0
[pid  4208] [ffffe410] write(1, "Password: ", 10Password: ) = 10
[pid  4208] [ffffe410] pause( 
[pid  4209] [ffffe410] close(4)         = 0
[pid  4209] [ffffe410] clone(Process 4210 attached
child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb7e486f8) = 4210
[pid  4209] [ffffe410] read(0,  
[pid  4210] [ffffe410] rt_sigaction(SIGINT, {0x80489db, [INT], SA_RESTART}, {SIG_DFL}, 8) = 0
[pid  4210] [ffffe410] rt_sigaction(SIGUSR2, {0x80489db, [USR2], SA_RESTART}, {SIG_DFL}, 8) = 0
[pid  4210] [ffffe410] rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
[pid  4210] [ffffe410] rt_sigaction(SIGCHLD, NULL, {SIG_DFL}, 8) = 0
[pid  4210] [ffffe410] rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
[pid  4210] [ffffe410] nanosleep({201527, 0}, 123
 
[pid  4209] [ffffe410] &lt;... read resumed&gt; "123\n", 128) = 4
[pid  4209] [ffffe410] write(3, "oops\n", 5oops
) = 5
[pid  4209] [ffffe410] kill(4210, SIGKILL 
[pid  4210] [ffffe410] &lt;... nanosleep resumed&gt; 0xbfcda008) = ? ERESTART_RESTARTBLOCK (To be restarted)
[pid  4209] [ffffe410] &lt;... kill resumed&gt; ) = 0
[pid  4210] upeek: ptrace(PTRACE_PEEKUSER,4210,48,0): No such process
[????????] +++ killed by SIGKILL +++
Process 4210 detached
[pid  4209] [ffffe410] getppid()        = 4208
[pid  4209] [ffffe410] --- SIGCHLD (Child exited) @ 0 (0) ---
[pid  4209] [ffffe410] kill(4208, SIGUSR1) = 0
[pid  4209] [08048d03] _exit(134521408) = ?
Process 4209 detached
[ffffe410] &lt;... pause resumed&gt; )        = ? ERESTARTNOHAND (To be restarted)
[ffffe410] --- SIGUSR1 (User defined signal 1) @ 0 (0) ---
[080488e7] --- SIGCHLD (Child exited) @ 0 (0) ---
[080488ef] _exit(134521408)             = ?
Process 4208 detached
</code></pre>
<p>
Looks better :)
</p>
<p>
So userinput is read in child1 (pid 4209):
</p>
<pre><code>[pid  4209] [ffffe410] read(0,  
.
[pid  4209] [ffffe410] &lt;... read resumed&gt; "123\n", 128) = 4
</code></pre>
<p>
and "oops" is also printed in child1
</p>
<pre><code>[pid  4209] [ffffe410] write(3, "oops\n", 5oops) = 5
</code></pre>
<p>
We should conentrate on child1, where password verification is done if we're lucky :)
</p>
<p>
Searching the fork call in disass. at 0x8048a8d and taking a look where child1 is called:
</p>
<pre><code>_08048a8d:  89 45 f0                mov    %eax,0xfffffff0  ; -16
_08048a90:  83 7d f0 00             cmpl   $0x0,0xfffffff0  ; -16
_08048a94:  0f 84 9a 00 00 00       je     _08048b34 
</code></pre>
<p>
Jump to child 1 must be here, since a value of 0 is returned only to the child process.
</p>
<p>
We'll take some risk and 'nop' the fork call and carry on with programflow at child1 directly.
</p>
<pre><code>$ cp pcme0_patched1  pcme0_patched1_no_parent
$ radare -cw ./pcme0_patched1_no_parent
warning: Opening file in read-write mode
open rw ./pcme0_patched1_no_parent
[0x000018E4]&gt; s 0xa88
0x00000A88
[0x00000A88]&gt; pD 20
0x00000A88 e88ffbffff              ^ call 0x61C   ;
0x00000A8D 8945f0                    [ebp-0x10] = eax
0x00000A90 837df000                  cmp dword [ebp-0x10], 0x0
[0x00000A88]&gt; wx 90 90 90 31 c0
[0x00000A88]&gt; pD 20
0x00000A88 90                        nop
0x00000A89 90                        nop
0x00000A8A 90                        nop
0x00000A8B 31c0                      eax ^= eax
0x00000A8D 8945f0                    [ebp-0x10] = eax
0x00000A90 837df000                  cmp dword [ebp-0x10], 0x0
[0x00000A88]&gt;q
</code></pre>
<p>
Now open pcme0_patched1_no_parent in debugger:
</p>
<pre><code>$ radare -cw dbg://pcme0_patched1_no_parent
warning: Opening file in read-write mode
argv = 'pcme0_patched1_no_parent',
Program 'pcme0_patched1_no_parent' loaded.
open debugger rw pcme0_patched1_no_parent
[0xB7F63810]&gt;  
</code></pre>
<p>
set a breakpoint at 0x08048a88 and run.
</p>
<pre><code>[0xB7F53810]&gt; !bp 0x08048a88
new breakpoint at 0x8048a88
[0xB7F53810]&gt; !run
To cleanly stop the execution, type: "^Z kill -STOP 4259 &amp;&amp; fg"
[pancrackme] v1.0
cont: breakpoint stop (0x8048a88)
[0xB7F53810]&gt;
</code></pre>
<p>
switch to debugger view:
</p>
<pre><code>[0xB7F53810]&gt; V

press 'p'
step with F7.
</code></pre>
<p>
after jumping to child1 first call is sys_open (you can see the written out syscall names in the disassembly (pcme0_1.s) which we have created earlier).
</p>
<pre><code>Disassembly:
0x08048B34 eip:
0x08048B34 83ec0c                    esp -= 0xc  ; 12
0x08048B37 6a04                      push 0x4
0x08048B39 e8cefaffff              ^ call 0x804860C   ; .._pcme0_pcme0_p+0x6
</code></pre>
<p>
jump over with F8.
</p>
<p>
Now here's a new call which does not show up in the disassembly.
</p>
<pre><code>0x08048B41 e8d6faffff              ^ call _0804861C  ; .._pcme0_pcme0_p+0x6
</code></pre>
<p>
As we can see by the address it calls, it is another sys_fork call. We can see where the child2 routine enters, by looking at the disassembly
</p>
<pre><code>0x08048B41 e8d6faffff              ^ call _0804861C    ; .._pcme0_pcme0_p+0x6
0x08048B46 8983cc000000              [ebx+0xcc] = eax
0x08048B4C 83bbcc00000000            cmp dword [ebx+0xcc], 0x0
_08048b53:  0f 84 f0 00 00 00       je     _08048c49 &lt;__gmon_start__@plt+0x4ed&gt; // -&gt;child2
</code></pre>
<p>
Child2 does'nt appear to have any passwordvalidation code, so why not take another risk and 'nop' this one too ? So step forward until eip is directly at the call
</p>
<pre><code>Disassembly:
0x08048B41 eip:
0x08048B41 e8d6faffff              ^ call 0x804861C   ; .._pcme0_pcme0_p+0x6

and type q.

[0x08048B41]&gt;
</code></pre>
<p>
here we remove the call. And we need to set %eax to &lt;&gt; 0, otherwise we will end up in child2's routine.
</p>
<pre><code>[0x08048B41]&gt; wx b8 01 00 00 00
[0x08048B41]&gt; pD 20
0x08048B41 eip:
0x08048B41 b801000000                eax = 0x1
0x08048B46 8983cc000000              [ebx+0xcc] = eax
[0x08048B41]&gt; V  
</code></pre>
<p>
type 'p' to switch from view from disassembly to debugger !
</p>
<p>
Back in debugger view, stepping further there's a sys_read call:
</p>
<pre><code>0x08048BBA e87dfbffff              ^ call 0x804873C   ; .._pcme0_pcme0_p+0x7
</code></pre>
<p>
Checking with ltrace we see it's the 'read user input' call:
</p>
<pre><code>[pid 4389] [0x8048bbf] read(0,  
[pid 4390] [0xffffe410] --- SIGSTOP (Stopped (signal)) ---
[pid 4390] [0xffffe410] --- SIGSTOP (Stopped (signal)) ---
123
[pid 4389] [0x8048bbf] &lt;... read resumed&gt; "123\n", 128)              = 4
</code></pre>
<p>
So we can check where the input buffer is. Step on just before the 'real' syscall.
</p>
<pre><code>Registers:
  eax  0x00000003    esi  0x00000002    eip    0xffffe405
  ebx  0x00000000    edi  0x00000002    oeax   0xffffffff
  ecx  0x0804a320    esp  0xbfb6e97c    eflags 0x200246
  edx  0x00000080    ebp  0xbfb6e97c    cPaZstIdor0 (PZI)
Disassembly:
0xFFFFE405 eip:
0xFFFFE405 0f34                      sysenter
</code></pre>
<p>
%eax = 3 standing for the sys_read call, %ebx is the file descriptor and %ecx is the pointer to the buffer. Now we have the input buffer, 0x0804a320 :)
</p>
<p>
use F10 to get back to user code. Since the call expects some input the debugger seams to hang, so just type any character and you will end up just behind the 'user input' call.
</p>
<p>
we can fill up the buffer with some random chars. Type q to leave debugger view, add some chars and type V,enter to get back to debugger mode and p to change to the correct view. Don't forget to terminate your data with 0x0a(return), as user input would have.
</p>
<pre><code>[0x08048BBF]&gt; s 0x0804a320
0x0804A320
[0x0804A320]&gt; wx 31 32 33 34 35 36 37 38 0a
[0x0804A320]&gt; x 10
   offset   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
.--------+-----------------------------------------+----------------
0x0804A320 3132 3334 3536 3738 0a00                 12345678..
[0x0804A320]&gt; V 
</code></pre>
<p>
Now we're at the interesting section :)) Step into the call.
</p>
<pre><code>0x08048BC9 e8e0fcffff              ^ call 0x80488AE   ; entry+0x13e
</code></pre>
<p>
and see what it does. first it checks if there is any input data available, otherwise jumps to return.
</p>
<pre><code>0x080488B7 803800                    cmp byte [eax], 0x0
0x080488BA 741f                    v jz 0x80488DB   ; eip+0x24
.
.
0x080488DB c745fc64000000            dword [ebp-0x4] = 0x64
0x080488E2 8b45fc                    eax = [ebp-0x4]
0x080488E5 c9                       leave ;--
0x080488E6 c3                       ret ;--
</code></pre>
<p>
Data from buffer pointer [ebp+0x8] is moved to %eax (movsx eax, byte [eax]) and it is tested for 0x0a(return) (cmp eax, 0xa).
</p>
<pre><code>0x080488BC 8b4508                    eax = [ebp+0x8]
0x080488BF eip:
0x080488BF 0fbe00                    movsx eax, byte [eax]
0x080488C2 83f80a                    cmp eax, 0xa
0x080488C5 750f                    v jnz 0x80488D6   ; eip+0x17
</code></pre>
<p>
otherwise the bufferpointer is increased and there's a loop, continuing with the next byte in buffer,
</p>
<pre><code>0x080488D6 ff4508                    dword [ebp+0x8]++
0x080488D9 ebd9                    ^ goto 0x80488B4   ; eip+0xf5
</code></pre>
<p>
until 0x0a is reached. And 0x0a is replaced with 0x0 in buffer at bufferpointer [ebp+0x8]. There is also this: 'dword [ebp-0x4] = 0x64' (or: [0xBFB6E994] = 0x64 ). We don't now what is needed for right now, but perhaps we should keep it in mind.
</p>
<pre><code>0x080488C2 83f80a                    cmp eax, 0xa
0x080488C5 750f                    v jnz 0x80488D6   ; eip+0x17
0x080488C7 8b4508                    eax = [ebp+0x8]
0x080488CA c60000                    byte [eax] = 0x0  ; 0
0x080488CD c745fc64000000            dword [ebp-0x4] = 0x64
0x080488D4 eb0c                    v goto 0x80488E2   ; eip+0x23
.
.
0x080488E2 8b45fc                    eax = [ebp-0x4]
0x080488E5 c9                       leave ;--
0x080488E6 c3                       ret ;--
</code></pre>
<p>
So all done here, was to replace the input terminating byte 0xa with 0x0.
</p>
<p>
Now we're back from this routine and there's a new call which we can step into.
</p>
<pre><code>0x08048BE0 e80cfdffff              ^ call 0x80488F1   ; entry+0x181
</code></pre>
<p>
but there is also a pretty intereseting structure right below. Looks like some printable characters :) and a write call
</p>
<pre><code>0x08048BE8 c683e40000000a            byte [ebx+0xe4] = 0xa  ; 10
0x08048BEF c683e40000000a            byte [ebx+0xe4] = 0xa  ; 10
0x08048BF6 c683e200000070            byte [ebx+0xe2] = 0x70  ; 112
0x08048BFD c683e10000006f            byte [ebx+0xe1] = 0x6f  ; 111
0x08048C04 c683e00000006f            byte [ebx+0xe0] = 0x6f  ; 111
0x08048C0B 8a83e2000000              al = [ebx+0xe2]
0x08048C11 83c003                    eax += 0x3  ; 3
0x08048C14 8883e3000000              [ebx+0xe3] = al
.
.
_08048c2c:  e8 cb f9 ff ff          call   _080485fc 
</code></pre>
<p>
So in order '6f 6f 70 70+3 0a' this prints: "oops". Now we now where we dont want to go. This means if we should return from our call we lost.
</p>
<p>
So, anyway. We step into the next call. The call that follows jumps right to the next instruction, so we just carry on
</p>
<pre><code>0x080488F8 e800000000              v call 0x80488FD   ; eip+0x5
0x080488FD 5b                        pop ebx
</code></pre>
<p>
The code below just pops into our eyes. More printable characters.
</p>
<pre><code>0x08048915 85c0                      test eax, eax
0x08048917 0f8589000000            ^ jnz dword 0x80489A6   ; eip+0xae
0x0804891D c683e100000065            byte [ebx+0xe1] = 0x65  ; 101
0x08048924 c683e200000065            byte [ebx+0xe2] = 0x65  ; 101
0x0804892B c683e300000068            byte [ebx+0xe3] = 0x68  ; 104
0x08048932 c683e000000079            byte [ebx+0xe0] = 0x79  ; 121
0x08048939 c683e40000000a            byte [ebx+0xe4] = 0xa  ; 10
0x08048940 80abe200000004            byte [ebx+0xe2] -= 0x4  ; 4
</code></pre>
<p>
Ordered: '79 65 65-4 68 0a' Printed out: "yeah". Probably here's where we need to end up. Seeing:
</p>
<pre><code>0x08048915 85c0                      test eax, eax
0x08048917 0f8589000000            ^ jnz dword 0x80489A6   ; eip+0xae
</code></pre>
<p>
we know we must return from our next call with %eax beeing 0.
</p>
<p>
As we step on, here's a strange sequence:
</p>
<pre><code>0x08048835 7501                    v jnz 0x8048838   ; eip+0x6
0x08048837 e88b450c03              v call 0xB10CDC7   ; eax+0x30c2aa7
0x0804883C 45                        ebp++
</code></pre>
<p>
An antidebugging trick. A jump to an address, which does not show up in our disassembly. So let's carry on steping. Some new code shows up.
</p>
<pre><code>0x08048838 8b450c                    eax = [ebp+0xc]
0x0804883B 034508                    eax += [ebp+0x8]
0x0804883E 0fbe10                    movsx edx, byte [eax]
0x08048841 8b83a8000000              eax = [ebx+0xa8]
0x08048847 83c03a                    eax += 0x3a  ; 58
0x0804884A 89d1                      ecx = edx
0x0804884C 31c1                      ecx ^= eax
0x0804884E 8d9386000000              lea edx, [ebx+0x86]
0x08048854 8b450c                    eax = [ebp+0xc]
0x08048857 0fbe0402                  movsx eax, byte [edx+eax]
0x0804885B 0fbe84037c000000          movsx eax, byte [ebx+eax+0x7c]
0x08048863 39c1                      cmp ecx, eax
0x08048865 7518                    v jnz 0x804887F   ; eip+0x47pre&gt;
</code></pre>
<p>
We were not able to see the code at 0x08048838 - 0x0804884A before. Most probably code which the programer did not want us to identify. This could be the clue :))) %eax is loaded with some kind of pointer:
</p>
<pre><code>0x08048838 8b450c                    eax = [ebp+0xc]
0x0804883B 034508                    eax += [ebp+0x8]
</code></pre>
<p>
%eax = 0x0804a320 . This is our input buffer.
</p>
<pre><code>0x0804883E 0fbe10                    movsx edx, byte [eax]
</code></pre>
<p>
one byte of input buffer [%eax] is moved to %edx . And some value (we don't now what this is need for yet) is moved to %eax and 0x3a is added to %eax:
</p>
<pre><code>0x08048841 8b83a8000000              eax = [ebx+0xa8]
0x08048847 83c03a                    eax += 0x3a  ; 58
</code></pre>
<p>
then our input data is moved to %ecx and %ecx is xored with %eax:
</p>
<pre><code>0x0804884A 89d1                      ecx = edx
0x0804884C 31c1                      ecx ^= eax
</code></pre>
<p>
This realy looks like the beginning of some kind of input validation :) Need to watch each step now.
</p>
<pre><code>0x0804884E 8d9386000000              lea edx, [ebx+0x86]
</code></pre>
<p>
The address %ebx+0x86 is stored in %edx, so this will be a pointer
</p>
<p>
%eax will also be a pointer for the next couple instructions. Since it's first value is 0 it is most likely an offset pointer.
</p>
<pre><code>0x08048854 8b450c                    eax = [ebp+0xc]
0x08048857 0fbe0402                  movsx eax, byte [edx+eax]
</code></pre>
<p>
After the first time through we end up having %eax=0 and %edx=0x0804a2c6. So we should take a look at memory at 0x0804a2c6 Type : to switch to commandline. Then:
</p>
<pre><code>:&gt; x 16 @ edx
   offset   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0 1 0123456789ABCDEF01
.--------+---------------------------------------------+-------------------
0x0804A2C6 0007 0402 0105 0906 0803 0a00 0000 1491      ................

--press any key--
</code></pre>
<p>
let's remember these couple of bytes. After any key, press p for debugger view.
</p>
<p>
Another location in memory we might want to remember is at [%ebx+0x7c] (0x0804a2bc). It may hold some data we were looking for, since %eax will be compared to our xored input data at the step after this one.
</p>
<pre><code>0x0804885B 0fbe84037c000000          movsx eax, byte [ebx+eax+0x7c]
</code></pre>
<p>
Do a print:
</p>
<pre><code>:&gt; x 16 @ ebx+0x7c
   offset   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0 1 0123456789ABCDEF01
.--------+---------------------------------------------+-------------------
0x0804A2BC 541a 5f1b 5949 220b 4e52 0007 0402 0105      T._.YI".NR......

--press any key--
</code></pre>
<p>
Wow ! This could be the key data, because at the next step our 0x3a-xored input code is compared to some data in %eax which came from this memory area.
</p>
<pre><code>0x08048863 39c1                      cmp ecx, eax
0x08048865 7518                    v jnz 0x804887F   ; eip+0x1c
0x08048867 83ec08                    esp -= 0x8  ; 8
0x0804886A 8b450c                    eax = [ebp+0xc]
0x0804886D 40                        eax++
0x0804886E 50                        push eax
0x0804886F ff7508                    push dword [ebp+0x8]
0x08048872 e8a5ffffff              ^ call 0x804881C   ; entry+0xac
</code></pre>
<p>
and if these bytes are equal, there's a call, back to beginning of the comparison routine. Change register %ecx, so that comparison will succeed. type : and
</p>
<pre><code>:&gt; !set ecx 0x54
--press any key--
</code></pre>
<p>
Check what our input must have been to get the value 0x54 at this point:
</p>
<pre><code>0x54 xor 0x3a = 0x6e = 'n'
</code></pre>
<p>
Set a break at 0x0804884C this is where our input data is xored.
</p>
<pre><code>0x0804884C 31c1                      ecx ^= eax
</code></pre>
<p>
and continue with F9
</p>
<p>
Next offset pointer is moved to %eax:
</p>
<pre><code>0x08048857 0fbe0402                  movsx eax, byte [edx+eax]

and data at [ebx+0x7c+offset-pointer] are loaded to %eax, to be compared to our input data.

0x0804885B 0fbe84037c000000          movsx eax, byte [ebx+eax+0x7c]
0x08048863 39c1                      cmp ecx, eax
</code></pre>
<p>
this time %eax=0x07, so looking back at:
</p>
<pre><code>:&gt; x 16 @ edx
   offset   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0 1 0123456789ABCDEF01
.--------+---------------------------------------------+-------------------
0x0804A2C6 0007 0402 0105 0906 0803 0a00 0000 1491      ................
</code></pre>
<p>
these seem to be the offset databytes and if we look again, at what could be the scrambled password:
</p>
<pre><code>:&gt; x 16 @ ebx+0x7c
   offset   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0 1 0123456789ABCDEF01
.--------+---------------------------------------------+-------------------
0x0804A2BC 541a 5f1b 5949 220b 4e52 0007 0402 0105      T._.YI".NR......

--press any key--
</code></pre>
<p>
We can make our first guess. Use the offset bytes at %edx (0x0804A2C6) byte for byte in order, to arrange the order of the password bytes. Should become: '54 0b 59 5f 1a 49 52 22 4e 1b 00'
</p>
<p>
Let's take a shot and xor all bytes with the mask 0x3a which is the mask already used twice now. Result: '6e 31 63 65 20 73 68 18 74 21 3a" looks like the scrambled password ends here. Would spell: "n1ce sh t!:" . Hey, almost dictionary words. We're real lucky :)))) But there's an unprintable character 0x18 and we can't be sure if this was all of the password.
</p>
<p>
We could search the binary for the first couple of scrambled bytes, upto the unprintable one. Let's use the radare.
</p>
<pre><code>$ radare ./pcme0
open ro ./pcme0
[0x00000000]&gt; /x 54 1a 5f 1b 59 49
1
[0x00000000]&gt; f
000 0x000012bc  512                        hit0[0]  54 1a 5f 1b 59 49 0a 0b 4e 52 00..
</code></pre>
<p>
Great :) Found the byte with 0x22 exchanged by 0x0a which is:
</p>
<p>
0x0b xor 0x3a = '0'
</p>
<p>
First password guess would be "n1ce sh0t!:"
</p>
<p>
So we'll try this one. Quit radare q, q, Y. !! All the patching done while running radare in debugger mode is lost !!, so load the file into radare:
</p>
<pre><code>&gt; radare -cw pcme0_patched1_no_parent
</code></pre>
<p>
and check if all patches above are in place. Otherwise redo them, quit radare and restart with debugger:
</p>
<pre><code>&gt; radare -cw dbg://pcme0_patched1_no_parent
</code></pre>
<p>
set a breakpoint right before the call where the user input terminator is replaced, and run. Type any character when debugger seems to hang after [pancrackme] v1.0 output.
</p>
<pre><code>&gt; radare -cw dbg://pcme0_patched1_no_parent
warning: Opening file in read-write mode
argv = 'pcme0_patched1_no_parent',
Program 'pcme0_patched1_no_parent' loaded.
open debugger rw pcme0_patched1_no_parent
[0xB7EEF810]&gt; !bp 0x08048bc9
new breakpoint at 0x8048bc9
[0xB7EEF810]&gt; !run
To cleanly stop the execution, type: "^Z kill -STOP 4681 &amp;&amp; fg"
[pancrackme] v1.0
1
cont: breakpoint stop (0x8048bc9)
</code></pre>
<p>
seek to input buffer location, write password bytes (use the one with the unprintable character, because that's the one that must match the scrambled password in memory, as long as we're running the patched binary) and doublecheck:
</p>
<pre><code>[0xB7EEF810]&gt; s 0x804a320
0x0804A320
[0x0804A320]&gt; wx 6e 31 63 65 20 73 68 18 74 21 3a 0a
   offset   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0 1  2 3  4 5  6 7  8 9 0123456789ABCDEF0123456789
.--------+-----------------------------------------------------------------+---------------------------
0x0804A320 6e31 6365 2073 6818 7421 3a0a 0000 0000                          n1ce sh.t!:.....
</code></pre>
<p>
Set a breakpoint at the location, where input and stored password bytes are compared.
</p>
<pre><code>[0x0804A320]&gt; !bp 0x08048863
new breakpoint at 0x8048863
</code></pre>
<p>
run and switch to debugger view when breakpoint was hit.
</p>
<pre><code>[0x0804A320]&gt; !run
To cleanly stop the execution, type: "^Z kill -STOP 4681 &amp;&amp; fg"
cont: breakpoint stop (0x8048863)
[0x0804A320]&gt; V
</code></pre>
<p>
%eax and %ecx must be equal to each other at the breakpoint, as long as new bytes are read from the input buffer and the buffer terminator 0x0 is not reached. Keep continuing with F9.
</p>
<pre><code>Registers:
  eax  0x00000059    esi  0x00000002    eip    0x08048863
  ebx  0x0804a240    edi  0x00000002    oeax   0xffffffff
  ecx  0x00000059    esp  0xbf90aa2c    eflags 0x0206
  edx  0x0804a2c6    ebp  0xbf90aa34    cPazstIdor0 (PI)
Disassembly:
0x08048863 eip:
0x08048863 39c1                      cmp ecx, eaxaybe 
...
</code></pre>
<p>
Something went wrong !
</p>
<pre><code>  eax  0x00000054    esi  0x00000002    eip    0x08048863
  ebx  0x0804a240    edi  0x00000002    oeax   0xffffffff
  ecx  0x0000003a    esp  0xbf90a90c    eflags 0x0206
  edx  0x0804a2c6    ebp  0xbf90a914    cPazstIdor0 (PI)
Disassembly:
0x08048863 eip:
0x08048863 39c1                      cmp ecx, eax
</code></pre>
<p>
we did not reach the terminator yet. Maybe the last character of the password is wrong. The ':' at the end strange anyway, "n1ce sh0t!:" . But let's keep on going to see what happens. Looks bad :( we need %eax to be 0x0 to go to the "yeah" output call.
</p>
<pre><code>Registers:
  eax  0x00000001    esi  0x00000002    eip    0x08048915
  ebx  0x0804a240    edi  0x00000002    oeax   0xffffffff
  ecx  0x0000003a    esp  0xbf90aa84    eflags 0x0296
  edx  0x0804a2c6    ebp  0xbf90aa8c    cPAzStIdor0 (PASI)
Disassembly:
0x08048915 eip:
0x08048915 85c0                      test eax, eax
0x08048917 0f8589000000            ^ jnz dword 0x80489A6   ; eip+0x91
0x0804891D c683e100000065            byte [ebx+0xe1] = 0x65  ; 101
0x08048924 c683e200000065            byte [ebx+0xe2] = 0x65  ; 101
0x0804892B c683e300000068            byte [ebx+0xe3] = 0x68  ; 104
0x08048932 c683e000000079            byte [ebx+0xe0] = 0x79  ; 121
0x08048939 c683e40000000a            byte [ebx+0xe4] = 0xa  ; 10
0x08048940 80abe200000004            byte [ebx+0xe2] -= 0x4  ; 4
0x08048947 83ec04                    esp -= 0x4  ; 4
0x0804894A 6a05                      push 0x5
0x0804894C 8d83e0000000              lea eax, [ebx+0xe0]
0x08048952 50                        push eax
0x08048953 ffb3c0000000              push dword [ebx+0xc0]
0x08048959 e89efcffff              ^ call 0x80485FC   ; .._pcme0_pcme0_p+0x5
</code></pre>
<p>
Need to check where %eax was set to 0x1: This could be somewhere just before we return, at the end of the password validation routine. Because this was the last routine that was called before %eax is tested fo 0x0.
</p>
<pre><code>_0804890d:  e8 0a ff ff ff          call   _0804881c 
;--
_08048912:  83 c4 08                add    $0x8,%esp
_08048915:  85 c0                   test   %eax,%eax
</code></pre>
<p>
probably here:
</p>
<pre><code>_0804889f:  c7 45 f8 01 00 00 00    movl   $0x1,0xfffffff8  ; -8
_080488a6:  8b 45 f8                mov    0xfffffff8  ; -8
_080488a9:  8b 5d fc                mov    0xfffffffc  ; -4
_080488ac:  c9                      leave
_080488ad:  c3                      ret
</code></pre>
<p>
Let's rerun, set a break and force an immediate error and watch what happens:
</p>
<pre><code> radare -cw dbg://pcme0_patched1_no_parent
warning: Opening file in read-write mode
argv = 'pcme0_patched1_no_parent',
Program 'pcme0_patched1_no_parent' loaded.
open debugger rw pcme0_patched1_no_parent
[0xB7FAB810]&gt; !bp 0x08048863     
new breakpoint at 0x8048863
[0xB7FAB810]&gt; !run
To cleanly stop the execution, type: "^Z kill -STOP 4684 &amp;&amp; fg"
[pancrackme] v1.0
1
cont: breakpoint stop (0x8048863)
[0xB7FAB810]&gt; V
</code></pre>
<p>
We're at the user input, password byte comparison location, steping on. We were right. We reach the location where %eax is set to 0x1 .
</p>
<pre><code>0x0804889F c745f801000000     dword [ebp-0x8] = 0x1
0x080488A6 8b45f8             eax = [ebp-0x8]
0x080488A9 8b5dfc             ebx = [ebp-0x4]
</code></pre>
<p>
Now we know we don't want to reach 0x0804889F but following code:
</p>
<pre><code>0x08048896 c745f800000000     dword [ebp-0x8] = 0x0
0x0804889D eb07             v goto 0x80488A6   ; entry+0x136
0x0804889F c745f801000000     dword [ebp-0x8] = 0x1
0x080488A6 8b45f8             eax = [ebp-0x8]
0x080488A9 8b5dfc             ebx = [ebp-0x4]
0x080488AC c9                 leave ;--
0x080488AD c3                 ret ;--
</code></pre>
<p>
We need to understand this part:
</p>
<pre><code>0x0804887F 0fbe8390000000            movsx eax, byte [ebx+0x90]
0x08048886 3b450c                    cmp eax, [ebp+0xc]
0x08048889 7514                    v jnz 0x804889F   ; entry+0x12f
0x0804888B 8b450c                    eax = [ebp+0xc]
0x0804888E 034508                    eax += [ebp+0x8]
0x08048891 803800                    cmp byte [eax], 0x0
0x08048894 7509                    v jnz 0x804889F   ; entry+0x12f
</code></pre>
<p>
Let's rerun. With the same breakpoint as before, but now taking a closer look at what happens at the section above. Here we need %eax to be 0x0 (as in location [ebp+0xc]) but it is 0x0a:
</p>
<pre><code>0x08048886 3b450c                    cmp eax, [ebp+0xc]
.
.
:&gt; x 1 @ ebp+0xc
   offset   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0 1 0123456789ABCDEF01
.--------+---------------------------------------------+-------------------
0xBFACA440 00                                           .

--press any key--
</code></pre>
<p>
So where is 0x0a moved to %eax ? must be here:
</p>
<pre><code>0x0804885B 0fbe84037c000000          movsx eax, byte [ebx+eax+0x7c]
</code></pre>
<p>
We must find out at which offset of the scrambled password we can find 0x0.
</p>
<pre><code>:&gt; x 16 @ ebx+0x7c
   offset   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0 1 0123456789ABCDEF01
.--------+---------------------------------------------+-------------------
0x0804A2BC 541a 5f1b 5949 220b 4e52 0007 0402 0105      T._.YI".NR......
</code></pre>
<p>
It is offset 0x0a. So 0x0a is the last offset byte we should move to %eax. This means our password is only allowed to have 10 characters (0-9). Lets try: "n1ce sh0t!".
</p>
<pre><code>&gt; radare -cw dbg://pcme0_patched1_no_parent
warning: Opening file in read-write mode
argv = 'pcme0_patched1_no_parent',
Program 'pcme0_patched1_no_parent' loaded.
open debugger rw pcme0_patched1_no_parent
[0xB7FD4810]&gt; !bp 0x08048bc9
new breakpoint at 0x8048bc9
[0xB7FD4810]&gt; !run
To cleanly stop the execution, type: "^Z kill -STOP 4719 &amp;&amp; fg"
[pancrackme] v1.0
1
cont: breakpoint stop (0x8048bc9)
[0xB7FD4810]&gt; s 0x804a320
0x0804A320
[0x0804A320]&gt; wx 6e 31 63 65 20 73 68 18 74 21 0a
[0x0804A320]&gt; x 11
   offset   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0 1  2 3  4 5  6 7  8 9 0123456789ABCDEF0123456789
.--------+-----------------------------------------------------------------+---------------------------
0x0804A320 6e31 6365 2073 6818 7421 0a                                      n1ce sh.t!.
[0x0804A320]&gt; !bp 0x0804887f
new breakpoint at 0x804887f
[0x0804A320]&gt; !run
To cleanly stop the execution, type: "^Z kill -STOP 4719 &amp;&amp; fg"
cont: breakpoint stop (0x804887f)
[0x0804A320]&gt; V
</code></pre>
<p>
looks good :)) %eax is 0x0. Thats what we need it to be.
</p>
<pre><code>Registers:
  eax  0x00000000    esi  0x00000002    eip    0x0804887f
  ebx  0x0804a240    edi  0x00000002    oeax   0xffffffff
  ecx  0x0000003a    esp  0xbfcfc51c    eflags 0x0206
  edx  0x0804a2c6    ebp  0xbfcfc524    cPazstIdor0 (PI)
Disassembly:
0x0804887F eip:
0x0804887F 0fbe8390000000            movsx eax, byte [ebx+0x90]
0x08048886 3b450c                    cmp eax, [ebp+0xc]

same here:

0x08048891 803800                    cmp byte [eax], 0x0
0x08048894 7509                    v jnz 0x804889F   ; eip+0xe
..
:&gt; x 1 @ eax
   offset   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0 1 0123456789ABCDEF01
.--------+---------------------------------------------+-------------------
0x0804A32A 00                                           .

--press any key--
</code></pre>
<p>
Finally made it :)))
</p>
<pre><code>yeah
User defined signal 1
</code></pre>
<p>
Just to make sure:
</p>
<pre><code>&gt; ./pcme0
[pancrackme] v1.0
Password: n1ce sh0t!
yeah
</code></pre>
<p>
That's it !
</p>
<p>
Thanks to Pancake for this great crackme. Had a lot of fun, eventhough this was a pretty tough one (at least for me) and learned some cool tricks :)
</p>
<p>
BTW, Pancake is also the guy who wrote radare and tools. Pretty fine tools for this kind of work :))
</p>

<!-- version IDs:
$Id: radare.but 2009-04-25 pancake $
-->
</body>
</html>