python - read file info, permissions from raw ext4 image - python

I am trying to unpack android 11 image / get info from the raw .img for selinux info, symlinks etc.
I am using this wonderful tool: https://github.com/cubinator/ext4/blob/master/ext4.py35.py
and my code looks like this:
#!/usr/bin/env python3
import argparse
import sys
import os
import ext4
parser = argparse.ArgumentParser(description='Read <modes, symlinks, contexts and capabilities> from an ext4 image')
parser.add_argument('ext4_image', help='Path to ext4 image to process')
args = parser.parse_args()
exists = os.path.isfile(args.ext4_image)
if not exists:
print("Error: input file " f"[{args.ext4_image}]" " was not found")
sys.exit(1)
file = open(args.ext4_image, "rb")
volume = ext4.Volume(file)
def scan_dir (root_inode, root_path = ""):
for entry_name, entry_inode_idx, entry_type in root_inode.open_dir():
if entry_name == "." or entry_name == "..":
continue
entry_inode = root_inode.volume.get_inode(entry_inode_idx)
entry_inode_path = root_path + "/" + entry_name
if entry_inode.is_dir:
scan_dir(entry_inode, entry_inode_path)
if entry_inode_path[-1] == '/':
continue
xattrs_perms = list(entry_inode.xattrs())
found_cap = False
found_con = False
if "security.capability" in f"{xattrs_perms}": found_cap = True
if "security.selinux" in f"{xattrs_perms}": found_con = True
contexts = ""
capability = ", \"capabilities\", 0x0"
if found_cap:
if found_con:
capability = f"{xattrs_perms[1:2]}"
else:
capability = f"{xattrs_perms[0:1]}"
capability = capability.split(" ")[1][:-3][+2:].encode('utf-8').decode('unicode-escape').encode('ISO-8859-1')
capability = hex(int.from_bytes(capability[4:8] + capability[14:18], "little"))
capability = ", \"capabilities\", " f"{capability}"
capability = f"{capability}"
if found_con:
contexts = f"{xattrs_perms[0:1]}"
contexts = f"{contexts.split( )[1].split('x00')[0][:-1][+2:]}"
contexts = f"{contexts}"
filefolder = ''.join(entry_inode_path.split('/', 1))
print("set_metadata(\""f"{filefolder}" "\", \"uid\", " f"{str(entry_inode.inode.i_uid)}" ", \"gid\", " f"{str(entry_inode.inode.i_gid)}" ", \"mode\", " f"{entry_inode.inode.i_mode & 0x1FF:0>4o}" f"{capability}" ", \"selabel\", \"" f"{contexts}" "\");")
scan_dir(volume.root)
file.close()
then I just have to do ./read.py vendor.img and it works.
Untill recently I tried this weird vendor.img from android 11 and got this weird issue.
Traceback (most recent call last):
File "./tools/metadata.py", line 53, in <module>
scan_dir(volume.root)
File "./tools/metadata.py", line 26, in scan_dir
scan_dir(entry_inode, entry_inode_path)
File "./tools/metadata.py", line 26, in scan_dir
scan_dir(entry_inode, entry_inode_path)
File "./tools/metadata.py", line 29, in scan_dir
xattrs_perms = list(entry_inode.xattrs())
File "/home/semaphore/unpacker/tools/ext4.py", line 976, in xattrs
for xattr_name, xattr_value in self._parse_xattrs(inline_data[offset:], 0, prefix_override = prefix_override):
File "/home/semaphore/unpacker/tools/ext4.py", line 724, in _parse_xattrs
xattr_inode = self.volume.get_inode(xattr.e_value_inum, InodeType.FILE)
NameError: name 'xattr' is not defined
I have tried removing the if and keeping code after else only here: https://github.com/cubinator/ext4/blob/master/ext4.py35.py#L722
Sadly no luck. It looks like the tool is not finished? But there are no other alternatives.
Any help is welcome :)
Thank you.
EDIT: someone suggested replace xattr with xattr_entry
So i did and i got this error: takes 2 positional arguments but 3 were given
I tried fixing that and got:
File "/home/semaphore/unpacker/tools/ext4.py", line 724, in _parse_xattrs
xattr_inode = self.volume.get_inode(xattr_entry.e_value_inum)
File "/home/semaphore/unpacker/tools/ext4.py", line 595, in get_inode
inode_table_offset = self.group_descriptors[group_idx].bg_inode_table * self.block_size
IndexError: list index out of range
And I could not fix this error :(
Maybe theres an alternative to getting selinux info, capabilities, uid, gid, permissions from raw ext4 image?

I read that you had tried to fix the issue yourself but you never posted a snippet of the code you're currently using.
I am not sure but it seems to me you modified the signature of get_inode instead of modifying which parameters get passed to it.
E.g. did you try:
xattr_inode = self.volume.get_inode(xattr_entry.e_value_inum)

I figured out how to do it in an alternative way.
First mount the image (needs root access):
os.system("sudo mount -t ext4 -o loop vendor.img vendor")
Then use: os.lstat and os.getxattr on each file. It gives all the information:
stat_info = os.lstat(file)
try:
cap = hex(int.from_bytes(os.getxattr(file, "security.capability")[4:8] + os.getxattr(file, "security.capability")[14:18], "little"))
except:
cap = "0x0"
try:
selabel = os.getxattr(file, b"security.selinux", follow_symlinks=False).decode().strip('\n\0')
except:
selabel = "u:object_r:unlabeled:s0"
metadata.append("set_metadata(\"/" + file + "\", \"uid\", " + str(stat_info.st_uid) + ", \"gid\", " + str(stat_info.st_gid) + ", \"mode\", " + oct(stat_info.st_mode)[-4:] + ", \"capabilities\", " + cap + ", \"selabel\", \"" + selabel + "\");")
Like so. This is the only solution I could find

Related

How to replace aws profile with new temporary credential with Python

I am writing a Python script that will use the .getsessiontoken() method and write the new temporary credentials to the aws credentials file at ~/.aws/credentials. The profile, in my case will be named [temp-token].
I can write to the file successfully, but then I thought, what if that profile already exists. I would have to find and replace subsequent lines after the profile name. I'm still new to Python and trying to understand what the problem is:
import os
import boto3 as b
mfa_serial_number = "arn:aws:iam::xxxxxxxxxxxx:mfa/your-iam-user-here"
mfa_otp = input("Enter your otp:" )
def get_sts(mfa_serial_number, mfa_otp):
session = b.Session(profile_name='default', region_name='us-east-1')
sts = session.client('sts')
if mfa_serial_number is not None:
response = sts.get_session_token(
SerialNumber=mfa_serial_number, TokenCode=mfa_otp)
else:
response = sts.get_session_token()
temp_credentials = response['Credentials']
print(temp_credentials)
token_reponse = ["[temp-token] \n", "aws_access_key_id = " + temp_credentials["AccessKeyId"], "\n", "aws_secret_access_key = " + temp_credentials["SecretAccessKey"],"\n", "aws_session_token = " + temp_credentials["SessionToken"],"\n"]
# Look for the temp-token profile
pfile = "[temp-token]"
with open("/Users/YOUR USER/.aws/credentials", "r") as credentials:
aws_credential_file = credentials.readlines()
#print(aws_credential_file)
for line in aws_credential_file:
if line.find(pfile) != -1:
print('Profile Exists!')
#Prints the line number where the word was found
profile_line = aws_credential_file.index(line)
new_aws_access_key_line_num = profile_line + 1
new_secret_access_key_line_num = profile_line + 2
new_session_token_key_line_num = profile_line + 3
print("its still working", profile_line)
print(new_aws_access_key_line_num)
aws_credential_file[new_aws_access_key_line_num] = "aws_access_key_id = " + temp_credentials["AccessKeyId"], "\n"
# aws_credential_file[new_secret_access_key_line_num] = "aws_secret_access_key = " + temp_credentials["SecretAccessKey"],"\n"
# aws_credential_file[new_session_token_key_line_num] = "aws_session_token = " + temp_credentials["SessionToken"],"\n"
#print()
else:
aws_credential_file.writelines(token_reponse)
credentials.close()
get_sts(mfa_serial_number, mfa_otp)
The error I get is:
its still working 3
4
Traceback (most recent call last):
File "/Users/YOUR USER/code/sts.py", line 49, in
get_sts(mfa_serial_number, mfa_otp)
File "/Users/YOUR USER/code/sts.py", line 29, in get_sts
if line.find(pfile) != -1:
AttributeError: 'tuple' object has no attribute 'find'
Is there a better way to do this?
It's because of the ,\n in aws_credential_file

Entity Draw with Understand Python API

I am trying to get each entity to draw a certain type of graph using the Understand Python API. All the inputs are good and the database is opened but the the single item is not drawn. There is no error and no output file. The code is listed below. The Python code is called from a C# application which calls upython.exe with the associated arguments.
The Python file receives the Scitools directory and opens the understand database. The entities are also an argument which is loaded into a temp file. The outputPath references the directory where the SVG file will be placed. I can't seem to figure out why the item.draw method isn't working.
import os
import sys
import argparse
import re
import json
#parse arguments
parser = argparse.ArgumentParser(description = 'Creates butterfly or call by graphs from and Understand DB')
parser.add_argument('PathToSci', type = str, help = "Path to Sci Understand libraries")
parser.add_argument('PathToDB', type = str, help = "Path to the Database you want to create graphs from")
parser.add_argument('PathToOutput', type = str, help='Path to where the graphs should be outputted')
parser.add_argument('TypeOfGraph', type = str,
help="The type of graph you want to generate. Same names as in Understand GUI. IE 'Butterfly' 'Called By' 'Control Flow' ")
parser.add_argument("entities", help='Path to json list file of Entity long names you wish to create graphs for')
args, unknown = parser.parse_known_args()
# they may have entered a path with a space broken into multiple strings
if len(unknown) > 0:
print("Unkown argument entered.\n Note: Individual arguments must be passed as a single string.")
quit()
pathToSci = args.PathToSci
pathToDB = args.PathToDB
graphType = args.TypeOfGraph
entities = json.load(open(args.entities,))
pathToOutput = args.PathToOutput
pathToSci = os.path.join(pathToSci, "Python")
sys.path.append(pathToSci)
import understand
db = understand.open(pathToDB)
count = 0
for name in entities:
count += 1
print("Completed: " + str(count) + "/" + str(len(entities)))
#if it is an empty name don't make a graph
if len(name) == 0:
break
pattern = re.compile((name + '$').replace("\\", "/"))
print("pattern: " + str(pattern))
sys.stdout.flush()
ent = db.lookup(pattern)
print("ent: " + str(ent))
sys.stdout.flush()
print("Type: " + str(type(ent[0])))
sys.stdout.flush()
for item in ent:
try:
filename = os.path.join(pathToOutput, item.longname() + ".svg")
print("Graph Type: " + graphType)
sys.stdout.flush()
print("filename: " + filename)
sys.stdout.flush()
print("Item Kind: " + str(ent[0].kind()))
sys.stdout.flush()
item.draw(graphType, filename)
except understand.UnderstandError:
print("error creating graph")
sys.stdout.flush()
except Exception as e:
print("Could not create graph for " + item.kind().longname() + ": " + item.longname())
sys.stdout.flush()
print(e)
sys.stdout.flush()
db.close()
The output is below:
Completed: 1/1
pattern: re.compile('CSC03.SIN_COS$')
ent: [#lCSC03.SIN_COS#kacsc03.sin_cos(long_float,csc03.sctype)long_float#f./../../../IOSSP/Source_Files/OGP/OGP_71/csc03/csc03.ada]
Type: <class 'understand.Ent'>
Graph Type: Butterfly
filename: C:\Users\M73720\Documents\DFS\DFS-OGP-25-Aug-2022-11-24\SVGs\Entities\CSC03.SIN_COS.svg
Item Kind: Function
It turns out that it was a problem in the Understand API. The latest build corrected the problem. This was found by talking with SciTools Support group.

Read config.py file from a compiled python .exe script

How do you make it so that an already compiled python script that was turned into a .exe import a config file?
Here is what I have:
#Rest of code that show the display and options are above ^
if __name__ == "__main__":
cwd = os.getcwd()
variableCheck = Path(cwd + '/config.py')
print(variableCheck)
print(cwd)
variableCheck.is_file()
if variableCheck.is_file():
from config import *
#Next print uses variables from config
print("ssh = " + ssh + "\nftp = " + ftp + "\nproftpd = " + proftpd + "\nvsftpd = " + vsftpd + "\nweb = " + web + "\napaweb = " + apaweb + "\nnginweb = " + nginweb + "\nhttps = " + https + "\nsmb = " + smb + "\nsql = " + sql + "\nrsnc = " + rsnc)
print('Configuration file has been loaded...')
app = QApplication(sys.argv)
main = Mainstart()
main.show()
sys.exit(app.exec_())
else:
print('Ello, you have some configurations to do!')
app = QApplication(sys.argv)
main = fconfStart()
main.show()
sys.exit(app.exec_())
I didn't add the functions fconfStart() or Mainstart() because 1) they are really long and 2) they are not the problem because they aren't even called yet when I get an error saying "cannot import config"
fconfStart function creates the config.py file.
First time the script is run you create the configurations file then you close and reopen the program to load with the configuration file that is config.py
How the config file is created in the first time startup of the script.
This is what happens when the confirm button is created (if it helps, I am using PyQt5 in this program):
#Rest of configuration options that users answer are above this piece of code ^
def confirmBTTN():
if self.ssh != '' and self.ftp != '' and self.proftpd != '' and self.vsftpd != '' and self.web != '' and self.apaweb != '' and self.nginweb != '' and self.https != '' and self.smb != '' and self.sql != '' and self.rsnc != '':
print('saving configurations\n')
print("ssh=" + self.ssh + ", ftp=" + self.ftp + ", proftpd=" + self.proftpd + ", vsftpd=" + self.vsftpd + ", web=" + self.web + ", apaweb=" + self.apaweb + ", nginweb=" + self.nginweb + ", https=" + self.https + ", smb=" + self.smb + ", sql=" + self.sql + ", rsnc=" + self.rsnc)
f = open("./config.py", "a+")
f.write("ssh = " + '"{}"'.format(self.ssh) + "\nftp = " + '"{}"'.format(self.ftp) + "\nproftpd = " + '"{}"'.format(self.proftpd) + "\nvsftpd = " + '"{}"'.format(self.vsftpd) + "\nweb = " + '"{}"'.format(self.web) + "\napaweb = " + '"{}"'.format(self.apaweb) + "\nnginweb = " + '"{}"'.format(self.nginweb) + "\nhttps = " + '"{}"'.format(self.https) + "\nsmb = " + '"{}"'.format(self.smb) + "\nsql = " + '"{}"'.format(self.sql) + "\nrsnc = " + '"{}"'.format(self.rsnc))
f.close()
RESTART = QMessageBox()
RESTART.setWindowTitle("Hey! Listen!")
RESTART.setText("Reopen the program to continue.")
RESTART.setIcon(QMessageBox.Information)
RESTART.setWindowIcon(QtGui.QIcon('HEY.png'))
RESTART.setStandardButtons(QMessageBox.Close)
RESTART.buttonClicked.connect(lambda: sys.exit(0))
x = RESTART.exec_()
else:
HEY = QMessageBox()
HEY.setWindowTitle('Hey! Listen!')
HEY.setText("Hey! You have not finished filling in all of the choices!")
HEY.setIcon(QMessageBox.Critical)
HEY.setWindowIcon(QtGui.QIcon('HEY.png'))
x = HEY.exec_()
Example Config.py
ssh = "yes"
ftp = "yes"
proftpd = "yes"
vsftpd = "no"
web = "yes"
apaweb = "yes"
nginweb = "no"
https = "yes"
smb = "yes"
sql = "yes"
rsnc = "no"
(If I need to use a different type of config file please let me know)
This is what the script creates. Then when I reopen script to use this newly created config file I get the error:
Traceback (most recent call last):
File "ScriptGUIrunner.py", line 380, in <module>
from config import *
ModuleNotFoundError: No module named 'config'
[20724] Failed to execute script ScriptGUIrunner
Can anyone help me with this problem?
Any help is greatly appreciated!
If you need me to add something to help clarify the problem I will gladly do so.
When you convert a python script to .exe you take away the ability to dynamically load python files (plus it can cause silent errors).
In general if you want to save information permanently then you should use any type of file (for example .txt) but it is better to use a pre-established format (such as .ini, .yaml, .csv, etc) and use a library that read safely such as ConfigParser, QSettings, etc.
On the other hand you should not use getcwd() but you should obtain the information dynamically as the answers to this question suggest.

Creating multipage tif in Freeimagepy, memory not being freed

I have created a program to merge TIFs into multipage tifs with an rather old version of FreeImagePy from 2009. It actually works pretty well but I have one little hitch. As best I can tell it's not freeing up the memory and eventually crashes. Can anyone tell me what I am missing?
Using Ptyhon 2.7.
import urllib
import FreeImagePy as FIPY
import os.path
import time
# set source files
sourceFile = open('C:\\temp\AGetStatePlats\\PlatsGenesee.csv','r')
# logfile currently gets totally replaced at each run
logFile = open('C:\\temp\\AGetStatePlats\\PlatTifMerge.txt','w')
sourcePath = "c:\\temp\subdownload2\\"
destPath = 'C:\\temp\\subtifMerge\\'
for row in sourceFile:
# prepare filenames
subPath = row.split(',',1)[0]
platID = subPath.split('/',1)[1]
curDocument = sourcePath + platID + '01.tif'
curPage = 0
# check if base file is out there
if not os.path.isfile(destPath + platID + '.tif'):
outImage = FIPY.Image()
outImage.new(multiBitmap = destPath + platID +'.tif')
print (destPath + platID +'.tif')
for n in range (1,100):
#build n
nPad = "{:0>2}".format(n)
if os.path.isfile(sourcePath + platID + nPad + '.tif'):
# delay in case file system is not keeping up may not be needed
time.sleep (1.0/4.0)
outImage.appendPage(sourcePath + platID + nPad + '.tif')
curPage = curPage + 1
else:
outImage.deletePage(0)
outImage.close()
del outImage
logFile.write(sourcePath + platID + '.tif' + '\r')
logFile.write(platID + " PageCount = " + str(curPage) + '\r' )
break
else:
logFile.write(platID + " already exists" + '\r')
# cleanup
sourceFile.close()
logFile.close()
print("Run Complete!")
Here's the error messages:
C:\temp\subtifMerge\05848.tif ('Error returned. ', 'TIFF', 'Warning: parsing error. Image may be incomplete or contain invalid data !') Traceback (most recent call last): File "C:\temp\AGetStatePlats\PlatTIFcombine.py", line 43, in outImage.appendPage(sourcePath + platID + nPad + '.tif') File "C:\Python27\ArcGIS10.4\lib\site-packages\FreeImagePy\FreeIm??agePy.py", line 2048, in appendPage bitmap = self.genericLoader(fileName) File "C:\Python27\ArcGIS10.4\lib\site-packages\FreeImagePy\FreeIm??agePy.py", line 1494, in genericLoader dib = self.Load(fif, fileName, flag); File "C:\Python27\ArcGIS10.4\lib\site-packages\FreeImagePy\FreeIm??agePy.py", line 188, in Load return self.__lib.Load(typ, fileName, flags)
WindowsError: exception: priviledged instruction >>>

How to make a file transfer program in python

The title might not be relevant for my question becuase I don't actually want a wireless file transfering script, I need a file manager type.
I want something with which I can connect my phone with my pc (eg: hotspot and wifi) and then I would like to show text file browser (I have the code for that) by sending lists of all files and folders using os.listdir(), whenever the selected option is a file (os.path.isdir() == False), I would like to transfer the file and run it(like: picture, video, etc).
The file Browser code which I wrote runs on windows and also Android (after making a few changes) using qpython.
My code is
import os
def FileBrowser(cwd = os.getcwd()):
while True:
if cwd[-1:] != "\\":
cwd = cwd + "\\"
files = os.listdir(cwd)
count = 1
tmpp = ""
print("\n\n" + "_"*50 +"\n\n")
print(cwd + "\n")
for f in files:
if os.path.isdir(cwd + f) == True:
s1 = str(count) + ". " + f
tmps1 = 40 - (len(s1)+5)
t2 = int(tmps1/3)
s1 = s1 + " " * t2 + "-" * (tmps1 - t2)
print(s1 + "<dir>")
else:
print(str(count) + ". " + f + tmpp)
count = count + 1
s = raw_input("Enter the file/Directory: ")
if s == "...":
tmp1 = cwd.count("\\")
tmp2 = cwd.rfind("\\")
if tmp1 > 1:
cwd = cwd[0:tmp2]
tmp2 = cwd.rfind("\\")
cwd = cwd[0:tmp2+1]
continue
else:
continue
else:
s = int(s) - 1
if os.path.isdir(cwd + files[s]) == True:
cwd = cwd + files[s] + "\\"
continue
else:
f1 = files[s]
break
return f1
def main():
fb = FileBrowser()
main()
A very naive approach using Python is to go to the root of the directory you want to be served and use:
python -m SimpleHTTPServer
The connect to it on port 8000.
you may need to socket programming. creating a link (connection) between your PC and you smart phone and then try to transfer files

Categories