|
23 | 23 | import java.awt.Image; |
24 | 24 | import java.awt.Transparency; |
25 | 25 | import java.awt.image.BufferedImage; |
| 26 | +import java.io.ByteArrayOutputStream; |
26 | 27 | import java.io.DataInputStream; |
27 | 28 | import java.io.File; |
28 | 29 | import java.io.FileInputStream; |
@@ -712,27 +713,39 @@ private static boolean noWebshellInPNG(File file) { |
712 | 713 | return false; |
713 | 714 | } |
714 | 715 |
|
715 | | - try (DataInputStream stream = new DataInputStream(new FileInputStream(file));) { |
716 | | - byte[] data = new byte[8]; |
717 | | - stream.readFully(data); //Read PNG Header |
| 716 | + try (DataInputStream stream = new DataInputStream(new FileInputStream(file))) { |
| 717 | + byte[] header = new byte[8]; |
| 718 | + stream.readFully(header); // Read PNG signature |
| 719 | + ByteArrayOutputStream idatBuffer = new ByteArrayOutputStream(); |
| 720 | + byte[] nameBuf = new byte[4]; |
718 | 721 | while (true) { |
719 | | - data = new byte[4]; |
720 | | - stream.readFully(data); //Read Length |
721 | | - int length = ((data[0] & 0xFF) << 24) |
722 | | - | ((data[1] & 0xFF) << 16) |
723 | | - | ((data[2] & 0xFF) << 8) |
724 | | - | (data[3] & 0xFF); //Byte array to int |
725 | | - stream.readFully(data); //Read Name |
726 | | - String name = new String(data); //Byte array to String |
| 722 | + byte[] lenBuf = new byte[4]; |
| 723 | + stream.readFully(lenBuf); // Read chunk length |
| 724 | + int length = ((lenBuf[0] & 0xFF) << 24) |
| 725 | + | ((lenBuf[1] & 0xFF) << 16) |
| 726 | + | ((lenBuf[2] & 0xFF) << 8) |
| 727 | + | (lenBuf[3] & 0xFF); |
| 728 | + stream.readFully(nameBuf); // Read chunk type |
| 729 | + String name = new String(nameBuf); |
727 | 730 | if (name.equals("IDAT")) { |
728 | | - data = new byte[length]; |
729 | | - stream.readFully(data); //Read Data |
730 | | - return inflate(data); |
731 | | - } else { //Don't care about other chunks |
732 | | - data = new byte[length + 4]; //Data length + 4 byte CRC |
733 | | - stream.readFully(data); //Skip Data and CRC. |
| 731 | + byte[] chunkData = new byte[length]; |
| 732 | + stream.readFully(chunkData); // Read data |
| 733 | + idatBuffer.write(chunkData); |
| 734 | + stream.readFully(new byte[4]); // Skip CRC |
| 735 | + } else if (name.equals("IEND")) { |
| 736 | + stream.readFully(new byte[4]); // Skip CRC |
| 737 | + break; // IEND marks end of PNG datastream |
| 738 | + } else { |
| 739 | + stream.readFully(new byte[length + 4]); // Skip data and CRC |
734 | 740 | } |
735 | 741 | } |
| 742 | + // Reject any bytes appended after IEND |
| 743 | + if (stream.read() != -1) { |
| 744 | + Debug.logError("================== Not saved for security reason, PNG has trailing bytes after IEND ==================", MODULE); |
| 745 | + return false; |
| 746 | + } |
| 747 | + // Inflate all concatenated IDAT chunks |
| 748 | + return inflate(idatBuffer.toByteArray()); |
736 | 749 | } catch (IOException error) { |
737 | 750 | Debug.logError("================== Not saved for security reason, wrong PNG IDAT (weird) ==================" + error, MODULE); |
738 | 751 | return false; |
|
0 commit comments