Fritz! Box 7490: วิธีอัปโหลดไฟล์กำหนดค่าที่แก้ไข


11

ฉันมีFritz! Box 7490 DSL / Modem / Router ที่อยู่อาศัยโดย AVM

หนึ่งสามารถถ่ายโอนการกำหนดค่าปัจจุบันของเราเตอร์เป็นไฟล์ (ภายใต้ "ระบบ> สำรองข้อมูล> บันทึกแท็บ") ผลที่ได้คือไฟล์ข้อความที่มีโครงสร้างอย่างง่ายไม่ใช่ JSON แต่เกือบจะเป็นเช่นนั้น(การตัดสินใจออกแบบยอดเยี่ยม AVM!)

ฉันต้องการแก้ไขโดยไม่ได้ตั้งใจและอัปโหลดอีกครั้งเพื่อเปลี่ยนการกำหนดค่าของเราเตอร์

ฉันต้องการแก้ไขอะไร ก่อนอื่นให้ล้างแคช DHCP ที่มีขนาดใหญ่มากในตอนนี้การทำสิ่งนี้ผ่านอินเทอร์เฟซนั้นใช้เวลานาน (ชั่วโมงในการคลิก) ขั้นที่สองปรับเปลี่ยนเซิร์ฟเวอร์ DNS ที่ส่งผ่านไปยังไคลเอนต์ DHCP บน LAN ตัวเลือก servercfg.user_dns1_for_ipv4และservercfg.user_dns2_for_ipv4ซึ่งไม่สามารถเข้าถึงได้ผ่านทางอินเทอร์เฟซ 7490

สิ่งอำนวยความสะดวกอัพโหลดการกำหนดค่าของเราเตอร์ ("ระบบ> สำรองข้อมูล> เรียกคืนแท็บ") แต่จะตรวจสอบความถูกต้องของไฟล์ เห็นได้ชัดว่ามันคำนวณ checksums จากเนื้อหาและตรวจสอบเหล่านี้กับ checksums ที่ฝังอยู่ในไฟล์ที่จะอัปโหลด นี่คือบรรทัดต่อไปนี้ที่ส่วนท้ายสุด:

**** END OF EXPORT 0428BE3C ****

หากมีความไม่ตรงกันการอัปโหลดจะถูกปฏิเสธด้วย "ไฟล์ที่ระบุไม่ใช่ไฟล์นำเข้าที่ถูกต้อง" (หากมีการจับคู่การอัปโหลดจะถูกนำไปใช้โดยไม่ต้องกังวลใจเพิ่มเติมและเราเตอร์จะรีบูต Ouch!)

ในรุ่น 7390 หนึ่งสามารถปิดการใช้งานการตรวจสอบความสมบูรณ์โดยการเพิ่มNoChecks=yesก่อนสตริงอินโทร**** CFGFILE:ar7.cfgที่ด้านบนสุด (ดูตัวอย่างการเปลี่ยน DNS บน Fritzbox ของคุณ ) เห็นได้ชัดว่ามันไม่ทำงานใน 7490 อีกต่อไป

มีวิธีแก้ไขอื่นเพื่อให้POKEรุ่นปัจจุบันนี้ใช้งานได้หรือไม่


เพื่อนร่วมงานได้พบจริงขั้นตอนวิธีการตรวจสอบการคำนวณที่ฟริตซ์! กล่อง VBScripte อืมมม ... ถึงเวลาทดสอบแล้ว (และเขียนเป็นภาษา Perl หรือไม่)
David Tonhofer

คุณสามารถตอบคำถามของคุณเองได้เช่นกัน
peterh - Reinstate Monica

เป็นไปได้ไหมที่จะตั้งค่าที่ UI ถูกปฏิเสธ? ตัวอย่างเช่นใช้พื้นที่ Unicode ทั้งหมดใน SSID หรือไม่
nikeee

@nikeee ฉันไม่มีความคิด อาจจะค่อนข้าง
David Tonhofer

คำตอบ:


12

นี่คือสคริปต์ที่ดูเหมือนจะคำนวณการตรวจสอบอย่างถูกต้องซึ่งกลายเป็น CRC32 การตรวจสอบ ในท้ายที่สุดฉันไม่ประสบความสำเร็จในการล้างแคช DHCP ของ Fritz! Box ผ่านการถ่ายโอนข้อมูล / แก้ไข / กู้คืนการกำหนดค่า ถอนหายใจ

#!/usr/bin/perl

# Read Fritz!Box configuration dump file and compute its checksum using CRC32.
# The problem is only knowing what to checksum exactly, and in this case its not pretty.
# Inspired from the very compact Visual Basic script by Michael Engelke available at
# http://www.mengelke.de/Projekte/FritzBoxVBScript 

# The Fritz!Box accepts a modified file where the checksum has been changed 
# manually to the output of this program in the last line. I have no idea what 
# happens if there is a syntax error anywhere inside the config file, so beware.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

use strict;
use warnings;

# ---
# Compute CRC start values
# ---

sub build_crc_table() {
   my @crctbl = (); # Accepts 256 values

   for (my $a = 0; $a < 256; $a++) {
      my $c = $a;
      for (my $b = 0; $b < 8; $b++) {
         my $d = $c & 0x01;
         $c = ($c >> 1) & 0x7FFFFFFF;
         if ($d) { 
            $c = $c ^ 0xEDB88320;
         }
      }
      push @crctbl, $c
   }

   my $print = 0;

   if ($print) {
      my $i = 0;
      foreach my $x (@crctbl) {
         print sprintf("CRC table value $i: %08x\n", $x);
         $i++
      }
   }

   return @crctbl
}

# ---
# Transform a string into a vector of its ASCII code points
# ---

sub numerize {
   my ($str) = @_;
   my @res = ();
   foreach my $ch (split('',$str)) {
      push @res, ord($ch)
   }
   return @res;
}

# ---
# Transform a hexstring into a vector of its 8-bit values
# ---

sub hexnumerize {
   my ($str) = @_;
   my @res = ();
   my $tmp;
   my $i = 0;
   foreach my $ch (split('',$str)) {
      if ($i == 0) { $tmp = $ch; $i++; }
      else         { $tmp.= $ch; $i=0; push @res,hex($tmp) } 
   }
   if ($i != 0) {
      die "Irregular hex string: $str\n";
   }
   return @res;
}

# ---
# Compute CRC-32 checksum
# See https://en.wikipedia.org/wiki/Cyclic_redundancy_check
# This must yield 414fa339:
# print sprintf("%08Xi\n", compute_crc32(numerize("The quick brown fox jumps over the lazy dog")));
# ---

sub compute_crc32 {
   my(@data)  = @_;
   my @crctbl = build_crc_table(); # not very efficient on multiple calls
   my $crc = 0xFFFFFFFF;
   my $i = 0;
   foreach my $x (@data) {
      my $index = ($crc ^ $x) & 0xFF;
      $crc = $crctbl[$index] ^ ($crc >> 8); # ">>" is zero-filling in Perl
      $crc = $crc & 0xFFFFFFFF;             # format to 32 bit
      #if ($i > 98700 && $i < 99000) {
      #   print sprintf("$i %c : $x => %08X\n",$x,$crc); 
      #}
      $i++
   }
   return $crc ^ 0xFFFFFFFF
}

# ---
# The name of the configuration file may have been given on the command line. 
# If so slurp the file.
# If nothing has been given, slurp STDIN.
# After that, the input can be found in "@lines" (line terminators are still in there)
# ---

my @lines;

if ($ARGV[0]) {
   open(my $fh,'<',$ARGV[0]) or die "Could not open file '$ARGV[0]': $!";
   @lines = <$fh>;
   close($fh)
}
else {
   @lines = <>;
}

# ---
# Stateful analysis.
# If there are lines after "END OF EXPORT" we will disregard them
# ---

my $firmware;       # will capture firmware version
my $fritzbox;       # will capture name string in header
my @data = ();      # will capture 8-bit values to be CRC-checksummed later
my $cursum;         # will capture the current CRC checksum in the text

# "state" indicates where we are in the file

my $state = 'NOTSTARTED';

# we consider the lines as a stack and push/pop to the stack

@lines = reverse @lines;

while (@lines && $state ne 'END') {

   my $line = pop @lines;

   if ($state eq 'NOTSTARTED') {
      if ($line =~ /^\*{4} (.*?) CONFIGURATION EXPORT/) {
         $fritzbox = $1;
         $state    = 'HEADER'
      }
      else {
         chomp $line;
         die "Expected 'CONFIGURATION EXPORT' in NOTSTARTED state, got '$line'"
      }
      next
   }

   if ($state eq 'HEADER') {
      chomp $line;
      if ($line =~ /(\w+)=([\w\$\.]+)$/) {
         my $key = $1;
         my $val = $2;
         if ($key eq 'FirmwareVersion') { $firmware = $val }
         push @data,numerize($key);
         push @data,numerize($val);
         push @data,0;
      }
      elsif ($line =~ /^\*{4}/) {
         $state = 'NEXTSECTION';
         push @lines,$line
      }
      else {
         die "Unexpected line in HEADER state: '$line'"
      }
      next
   }

   if ($state eq 'NEXTSECTION') {
      chomp $line;
      if ($line =~ /^\*{4} (?:CRYPTED)?(CFG|BIN)FILE:(\S+)/) {
         $state = "INSIDESECTION_$1";
         my $secname = $2;
         print "Section $line\n";
         push @data,numerize($secname);
         push @data,0
      }   
      elsif ($line =~ /^\*{4} END OF EXPORT (\w{8}) \*{4}/) {
         $state  = 'END';
         $cursum = $1
      }
      else {
          die "Unexpected line in NEXTSECTION state: '$line'"
      }
      next
   }

   if ($state eq 'INSIDESECTION_BIN') {
      chomp $line;
      if ($line =~ /^\*{4} END OF FILE \*{4}/) {
         $state = 'NEXTSECTION'
      } 
      else {
         push @data,hexnumerize($line)
      } 
      next
   }

   if ($state eq 'INSIDESECTION_CFG') {
      if ($line =~ /^\*{4} END OF FILE \*{4}/) {
         # Something unbelievably dirty: All section-internal linefeeds (and carriage returns)
         # are kept as is for checksumming, except for the last one before the "END OF FILE"
         if ($data[-1] == ord("\n")) {
            pop @data;
            if ($data[-1] == ord("\r")) {
               pop @data;
            }
         }
         $state = 'NEXTSECTION'
      }
      else {
         # More dirty stuff: Double backspaces are replaced by single ones for some reason.
         $line =~ s/\\\\/\\/g;
         push @data,numerize($line)
      }
      next
   } 

   die "Unexpected state $state"

}

if ($state ne 'END') {
   die 'Did not find proper end of configuration'
}
if (@lines) {
   my $n = @lines;
   print "There are still $n lines left that will be disregarded"
}

my $crc = compute_crc32(@data);
my $newsum = sprintf("%08X", $crc);

print "$fritzbox with firmware $firmware\n";

if ($newsum eq $cursum) {
   print "Checksum is OK: $cursum\n"
}
else {
   print "Found new checksum: $newsum\n";
   print "Checksum embedded in file is $cursum\n"
}

1
ทดสอบสคริปต์ด้วย Fritz! Box 7390 ของฉันและสามารถอัปโหลดการกำหนดค่าที่แก้ไขได้
กาแล็กซี่

เครื่องมือที่ยอดเยี่ยม! ยืนยัน (อย่างที่กาแล็กซี่ทำ) มันยังคงใช้งานได้กับ 7390 เฟิร์มแวร์ของฉัน: 6.30 :)
Madivad

3
ตรวจสอบเวอร์ชั่นของไพ ธ อน (รวม win32 exe gui) ที่สร้างไว้ล่วงหน้าได้ที่github.com/mementum/fritzchecksum
ระลึก

1
@ David ดีจริงๆขอบคุณมาก ฉันสามารถยืนยันได้ว่านี่เป็นการทำงานกับ LAB-BETA (6.69) ของ F! Box 7490
Kev Inski
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.