1

I am looking for a way to implement the __toString method using only eval in PHP. The end goal is to be able to read a file. Note that this is part of a CTF challenge and not a real world application.

I am given the following implementation

function __toString(){
     eval($this->var);
}

Since $var is under my control I can set if to whatever I want. So far I've tried the following without success:

$var = "return file_get_contents('file.txt');"

Any hints?

UPDATE: The relevant code looks as follows:

class MyClass{
    private $var;
    function __toString(){
        if (isset($this->var) eval($this->var);
    }
}
Marc Ilunga
  • 121
  • 6

2 Answers2

0

If you check the doc, you will see that function __toString() must return a string. So whatever you do inside of the __toString() method, just make sure that you return a string. It's great that you have mentioned that this is not for a real world application. Because eval() can be quite dangerous and can give unexpected results.

Also, if va is really under your control, why not just do the following ...

$this->var = file_get_contents('file.txt');
//...
function __toString(){
     return $this->var;
}

One final thought ... If you are doing $var = "return file_get_contents('file.txt');", that's not the same thing as doing $this->var = "return file_get_contents('file.txt');"

asiby
  • 3,229
  • 29
  • 32
0

You could echo inside $var itself.

$var = "echo file_get_contents('input.txt');";

If you don't want to print anything on the screen and just get the file contents, you could use output buffering. I used ob_start() and ob_get_clean().

<?php

$var = "ob_start();echo file_get_contents('input.txt');";

eval($var);// your __toString() function call here.

$file_contents = ob_get_clean();

echo $file_contents;
nice_dev
  • 17,053
  • 2
  • 21
  • 35
  • That looks nice! I tried it locally, I get an error but the echo still goes through, but It's not working on the remote server. After some digging I found out that the remote server is running PHP 5.5.9. In the challenge I get a 'Terminal output' where I can see the errors – Marc Ilunga Apr 22 '19 at 14:09
  • @MarcIlunga Can you share the challenge link? Also, PHP version shouldn't be an issue. – nice_dev Apr 22 '19 at 14:16
  • Unfortunately I can't really share the challenge link since it is private. What I don't understand is that locally it throws a recoverable error but still prints the value and remotely it doesn't print anything – Marc Ilunga Apr 22 '19 at 15:07
  • @MarcIlunga I can't tell you much without looking at the challenge myself. Also, the code I pasted works perfectly fine on my machine. There is a possibility that output buffering feature might be turned off on the server your code is getting executed on. – nice_dev Apr 22 '19 at 15:47
  • I have updated the question with the only portion of the source code that I got. This is really the only thing I've got in this challenge – Marc Ilunga Apr 22 '19 at 16:04
  • @MarcIlunga So, can you modify the value inside `$this->var` ? Do they provide any getters and setters for that? – nice_dev Apr 22 '19 at 16:07
  • No, no getter nor setters provided.. What I try to do is recreate the class locally and set ```$this->hook``` to the code I want. Then, I create an object and serialize it. So I end up with a payload like this: ```O:8:"Myclass":1:{s:14:" MyClass var";s:25:"ob_start(); print_flag();";}``` – Marc Ilunga Apr 22 '19 at 16:27
  • 1
    Thanks for hanging on with me. ;). I'll move the discussion to chat – Marc Ilunga Apr 22 '19 at 16:27
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/192226/discussion-between-marc-ilunga-and-vivek-23). – Marc Ilunga Apr 22 '19 at 16:28
  • @MarcIlunga I am unable to understand your code and it's context. – nice_dev Apr 22 '19 at 16:34