PHP yang dapat dieksekusi akan berjalan di baris perintah tetapi tidak di browser

Jadi menggunakan 'php index.php' memberi saya output yang saya inginkan di baris perintah. Namun tidak akan memberikan output pada halaman web. Jadi pertama-tama saya memiliki file python yang pada dasarnya melakukan semua yang saya inginkan:

import subprocess

subprocess.call("sudo nmap -sP 192.168.1.0/24 > /home/pi/whohome.txt", shell=True)

searchfile = open("/home/pi/whohome.txt", "r")
for line in searchfile:
    if "android-5ab6eb374b5fd6" in line: print "Jeremy is home (phone)"
    if "Jeremys-MBP" in line: print "Jeremy is home (computer)"
    if "LMCMs-iPhone" in line: print "Liam is home (phone)"
    if "Liam" in line: print "Liam is home (computer)"
    if "android-4a186cbbeb2c5229" in line: print "Lara is home (phone)"
    if "LaraD" in line: print "Lara is home (computer)"
    if "KristiansiPhone" in line: print "Martin is home (phone)"
    if "Martins-MBP" in line: print "Martin is home (computer)"

searchfile.close()

Kedua, saya hanya memiliki sh yang dapat dieksekusi yang akan memasukkan output dari perintah python ini ke file teks lain:

python /home/pi/myRoomMates.py > /var/www/html/website.txt

Saya kemudian memiliki file php di server web Apache yang berjalan di raspberry pi, bunyinya:

<?php
shell_exec('/home/pi/whoishome.sh');

echo file_get_contents ("/var/www/html/website.txt");

?>

Jadi kalau tidak salah, setiap halaman di-refresh harus mengeksekusi itu, tunggu sampai exec selesai, lalu tampilkan isi file txt? Saya telah mencoba shell_exec dan exec, keduanya melakukan hal yang sama..


person Jeremy de Rooy    schedule 23.05.2016    source sumber
comment
saya bertaruh pada izin.   -  person    schedule 23.05.2016
comment
Saya menggandakan taruhan @Dagon   -  person Darren    schedule 23.05.2016
comment
@ Darren kita tidak bisa kalah, saya punya sistem   -  person    schedule 23.05.2016
comment
@Dagon Oke, saya baru saja melakukan chmod 777, pada kedua direktori, direktori /home/pi/ dan direktori /var/www/html. Yang sepertinya telah melakukan sesuatu karena sekarang file website.txt berubah, tetapi setiap kali saya menyegarkan halaman web, file txt akan kosong. Namun jika saya menjalankan php melalui baris perintah, itu memberikan output yang benar di file txt..   -  person Jeremy de Rooy    schedule 23.05.2016
comment
Saya tidak tahu apakah OS Raspberry Pi menyertakan ekstensi keamanan SELinux, tetapi jika ya (dan diaktifkan), maka mungkin saja satu atau lebih file keluaran tersebut dibuat dalam konteks keamanan yang membuatnya tidak terlihat oleh Apache (atau ke salah satu proses yang muncul, seperti python atau bash). Itu mungkin menjelaskan bagaimana website.txt menjadi kosong (atau tampak kosong). Periksa konteks keamanan file dengan ls -Z *whatever*.   -  person Kevin J. Chase    schedule 23.05.2016
comment
@KevinJ.Chase Hanya memberi tanda tanya di sebelah file, tetapi mencari di Google cara menonaktifkan SELinux dan melakukan perintah tersebut tetapi sepertinya SELinux tidak ada di mana pun di sistem.   -  person Jeremy de Rooy    schedule 23.05.2016
comment
Apakah file website.txt benar-benar terpotong menjadi 0 byte saat Anda memuat ulang halaman? Itu berarti skrip python sedang berjalan, tetapi menghasilkan output 0 byte. Apakah ada masukan berharga dalam file whohome.txt?   -  person Kevin J. Chase    schedule 23.05.2016
comment
@KevinJ.Chase mengirimkan keduanya dengan nol byte setelah halaman dimuat ulang, tetapi ketika php dijalankan di baris perintah, keduanya berisi keluaran yang benar. Jadi perintah python berfungsi seperti itu, hanya menghasilkan output 0..   -  person Jeremy de Rooy    schedule 23.05.2016
comment
@ KevinJ.Chase, Maaf saya baru mengenal pemrograman dan apa yang tidak, tapi apakah itu akan menggantikan bagian 'file pencarian'? Apakah Anda dapat menunjukkan kepada saya seperti apa tampilan file python dengan subproses.check_output itu. Dan di mana saya bisa merujuk ke keluaran itu untuk meletakkannya di server web?   -  person Jeremy de Rooy    schedule 23.05.2016
comment
Lihat jawaban saya untuk contoh kode.   -  person Kevin J. Chase    schedule 23.05.2016
comment
Jangan lupa untuk mengembalikan izin yang masuk akal ke semua file dan direktori yang telah Anda chmodedit ke 0777, dan secara umum untuk mengaktifkan kembali keamanan apa pun yang telah Anda nonaktifkan saat memecahkan masalah ini.   -  person Kevin J. Chase    schedule 23.05.2016


Jawaban (2)


Ada banyak hak, Anda harus memastikan:

  1. pengguna Apache harus berada di grup sudoers
  2. pengguna apache harus menulis ke /home/pi/whohome.txt
  3. pengguna apache harus menulis ke /var/www/html/website.txt
  4. /home/pi/whoishome.shharus dapat dieksekusi oleh pengguna apache

Untuk poin 1 hingga 3, biasanya bukan ide yang baik untuk memberikan hak ini kepada pengguna Apache.

Anda dapat membuatnya lebih mudah jika Anda memulai skrip python sebagai CGI:

import subprocess

ADDRESS = "192.168.1.0/24"

USERS = {
    "android-5ab6eb374b5fd6": ("Jeremy", "phone"),
    "Jeremys-MBP": ("Jeremy", "computer"),
    "LMCMs-iPhone": ("Liam", "phone"),
    "Liam": ("Liam", "computer"),
    "android-4a186cbbeb2c5229": ("Lara", "phone"),
    "LaraD": ("Lara", "computer"),
    "KristiansiPhone": ("Martin", "phone"),
    "Martins-MBP": ("Martin", "computer"),
}


nmap = subprocess.Popen(["sudo", "nmap", "-sP", ADDRESS], stdout=subprocess.PIPE)
for line in nmap.stdout:
    for user, name in USERS.items():
        if user in line:
            print "%s is home(%s)" % name
nmap.wait()

Hanya poin 1 dan 4 yang harus dipenuhi.

person Daniel    schedule 23.05.2016

Saya menduga masalah Anda adalah bagian sudo dari baris perintah nmap. Jika Anda mengganti subprocess.call dengan subprocess.check_call, saya rasa Anda akan menemukannya perintah itu memunculkan CalledProcessError.

Agaknya, akun pengguna Anda ada di file /etc/sudoers, namun server Web tidak.

Karena hal pertama yang dilakukan oleh operator pengalihan keluaran shell (>) adalah memotong file keluaran, upaya yang gagal untuk menjalankan nmap menghasilkan whohome.txt nol-byte. Skrip Python lainnya kemudian melakukan hal yang sama pada website.txt, dan Anda tidak mendapatkan apa pun untuk ditampilkan di situs Web Anda.

Solusi

Tidak diperlukan sudo.

Di desktop Linux saya, Saya tidak perlu menjalankan nmap sebagai root untuk melakukan pemindaian ping lokal. Jika itu benar pada sistem Anda, maka Anda seharusnya bisa membuang bagian sudo dari perintah nmap Anda, dan selesai.

Namun ada perbedaannya. nmap akan melakukan pengujian yang lebih menyeluruh terhadap setiap target ketika sapuan -pS ping dijalankan oleh root. Dari halaman manual nmap lama (penekanan ditambahkan):

-sP (Lewati pemindaian port) .

[...]

Opsi -sP mengirimkan permintaan gema ICMP, TCP SYN ke port 443, TCP ACK ke port 80, dan permintaan stempel waktu ICMP secara default. Ketika dijalankan oleh pengguna yang tidak memiliki hak istimewa, hanya paket SYN yang dikirim (menggunakan panggilan connect) ke port 80 dan 443 pada target. Ketika pengguna yang memiliki hak istimewa mencoba memindai target di jaringan ethernet lokal, permintaan ARP akan digunakan kecuali --send-ip ditentukan. [...]

Aktifkan sudo untuk server Web Anda.

Jika Anda memerlukan informasi tambahan ini (dan sepertinya memang demikian), Anda harus menjalankan nmap (atau skrip Python yang memanggilnya) dengan hak pengguna super. Saya tidak pernah mencoba memaksa server Web untuk melakukan ini, tapi saya berasumsi Anda setidaknya harus menambahkan pengguna server Web Anda ke /etc/sudoers. Sesuatu seperti:

apache    localhost=/usr/bin/nmap -sP

or:

httpd    ALL=/usr/local/bin/nmap

...dan seterusnya, bergantung pada nama pengguna, di mana nmap Anda berada, seberapa ketat Anda ingin membatasi argumen ke nmap, dll.

Buat SUID yang dapat dieksekusi untuk menjalankan nmap untuk Anda.

Alternatifnya (dan saya benci diri saya sendiri karena merekomendasikan hal ini --- pasti ada cara yang lebih baik) adalah dengan menulis program SUID (Set User ID) kecil yang hanya mengeksekusi nmap perintah yang kamu inginkan. Berikut program C yang akan melakukannya:

#include <stdio.h>
#include <unistd.h>

int main(void);

int main(void) {
    int retval = 0;
    char* const error_string = "ERROR: Failed to execute \"/usr/bin/map\"";
    char* const nmap_args[] = {
      "/usr/bin/nmap",
      "-sP",
      "192.168.1.0/24",
      NULL
    };

    retval = execv("/usr/bin/nmap", nmap_args);
    /* execv returns _only_ if it fails, so if we've reached this
     * point, print an error and exit.
     */
    perror(error_string);
    return retval;
}

Simpan di atas sebagai sesuatu seperti nmap_lan.c, dan kompilasi dengan:

$ gcc -Wall -o nmap_lan nmap_lan.c

Lalu, pindahkan ke mana pun Anda menyimpan skrip situs Web Anda, dan sebagai root, ubah kepemilikan dan izinnya:

# chown root:root nmap_lan  # Or whatever group name you use.
# chmod 4555 nmap_lan

4 di depan menyetel bit SUID. Warna ls dari direktori mungkin akan menampilkan file yang disorot. Izinnya akan terlihat seperti ini:

# ls -l nmap_lan
-r-sr-xr-x. 1 root root 6682 May 23 03:04 nmap_lan

Setiap pengguna yang menjalankan nmap_lan akan dipromosikan sementara menjadi pemilik file nmap_lan (dalam hal ini, root) hingga program keluar. Itu luar biasa murah hati, itulah sebabnya saya mengkodekan semuanya dalam program itu dengan keras... Untuk mengubah apa pun yang dilakukannya --- bahkan hanya rentang IP yang akan dipindai --- Anda harus mengedit nmap_lan.c file, kompilasi ulang, dan instal ulang.

Saya telah menguji nmap_lan pada baris perintah saya, dan menghasilkan keluaran nmap pengguna yang memiliki hak istimewa ketika dijalankan oleh pengguna yang tidak memiliki hak istimewa yang biasanya hanya mendapat keluaran terbatas.

Komentar pada skrip Python

Secara umum, Python jauh lebih baik dalam mengurai argumen shell dibandingkan shell (nilai default untuk shell adalah False karena suatu alasan), jadi buatlah skrip Python Anda melakukan pekerjaan sebanyak mungkin, termasuk menguraikan perintah shell, mengarahkan input, dan mengarahkan output.

Keuntungan utama melakukan pekerjaan dengan Python adalah kegagalan membuka, membaca, menulis, atau menutup file Anda akan mengakibatkan crash langsung dan jejak tumpukan --- alih-alih kegagalan diam-diam yang selama ini Anda alami.

Saya akan menulis ulang perintah call untuk menggunakan daftar argumen yang dipisahkan secara eksplisit. Anda dapat menangani pengalihan keluaran dengan meneruskan aliran file yang dibuka ke parameter stdout. Anda dapat menghilangkan sedikit pengalihan shell terakhir dengan meminta Python membuka file output Anda dan menulisnya secara eksplisit.

nmap_file='/home/pi/whohome.txt'
with open(nmap_file, 'wt', encoding='ascii') as fout:
    subprocess.call(
      ['/usr/bin/nmap', '-sP', '192.168.1.0/24'],  # Or just ['nmap_lan']
      stdout=fout,
      universal_newlines=True,
      )

output_file='/var/www/html/website.txt'
with open(nmap_file, 'rt', encoding='ascii') as fin:
    with open(output_file, 'wt', encoding='ascii') as fout:
        for line in fin:
            ...
            print('Output here', file=fout)  # Add `file=...` to each print.

Selain itu, kecuali Anda memerlukan file whohome.txt tersebut untuk hal lain, Anda dapat menghilangkannya seluruhnya dengan menggunakan check_output untuk menyimpan output dari perintah nmap sebagai string, dan kemudian membaginya menjadi baris terpisah. (Parameter universal_newlines juga menangani konversi objek bytes menjadi str, setidaknya dengan Python 3.)

lines = subprocess.check_output(
  ['/usr/bin/nmap', '-sP', '192.168.1.0/24'],  # Or just ['nmap_lan']
  universal_newlines=True
  ).split('\n')

output_file='/var/www/html/website.txt'
with open(output_file, 'wt', encoding='ascii') as fout:
    for line in lines:
        ...
        print('Output here', file=fout)  # Add `file=...` to each print.

Perhatikan bahwa saya menggunakan with blok untuk menutup file secara gratis.

(Akhirnya, rangkaian perintah if tersebut meminta untuk ditulis ulang sebagai perulangan for machine in machines_dict:, dengan string yang Anda cari sebagai kunci dalam kamus tersebut, dan keluaran yang ingin Anda cetak sebagai nilainya.)

person Kevin J. Chase    schedule 23.05.2016
comment
Legenda mutlak, Anda benar, itu adalah perintah sudo. Tidak sepenuhnya yakin mengapa saya memiliki sudo untuk nmap karena ia berfungsi tanpanya. Tapi menghapus sudo dan semuanya berhasil. Terima kasih Kevin! - person Jeremy de Rooy; 23.05.2016
comment
Satu-satunya hal adalah, menjalankan nmap sebagai sudo diperlukan karena beberapa perangkat tidak muncul pada pemindaian nmap jika tidak dijalankan sebagai sudo.. - person Jeremy de Rooy; 23.05.2016
comment
@JeremydeRooy: Saya telah memperbarui jawaban saya. Saya tidak dapat dengan mudah atau andal menguji sudo di bawah Apache pada pengaturan yang saya miliki, jadi saya tidak dapat melakukan lebih dari sekadar menunjuk ke /etc/sudoers (dan mungkin menyertakan file di bawah /etc/sudoers.d/), dan menyarankan agar pengguna Apache Anda memerlukan izin untuk menjalankan nmap atau skrip Python Anda melalui sudo. (Alternatifnya adalah dengan menulis program Set-User-ID (SUID) kecil yang hanya nmap -sP ... berjalan, namun Anda ingin melakukannya dalam bahasa yang dikompilasi seperti C. Skrip SUID sangat sulit untuk dijalankan. aman (dan skrip SUID shell pada dasarnya tidak mungkin diamankan). - person Kevin J. Chase; 23.05.2016
comment
@JeremydeRooy: Saya telah menambahkan program SUID ke jawaban saya sebagai solusi ketiga yang mungkin. (Tapi saya benci. Pasti ada cara untuk melakukan ini menggunakan Apache, atau PHP, atau sudo, atau... apa pun.) - person Kevin J. Chase; 23.05.2016
comment
Sial, ini jawaban yang mengesankan - bagus! - person Darren; 24.05.2016